typedef or derive?

E

eiji

Hi folks,

I found this code in a project:
class TestList : public std::vector<Test> { /*empty!!!*/ };

Basicly this ends up in the same result like
typedef std::vector<Test> TestList; ?

So is there a real benefit of the first version, and I have no idea?
I think the first ends up in slower code!?
Does a good compiler optimize the first case into the second?

And last but not least, have a look at this:

somePtr t* = new somePtr( );
....
delete t;
t = NULL;

I know, NULL is windows style, but is that necessary?

Thanks a lot!!

Regards,
Sascha
 
V

Victor Bazarov

eiji said:
I found this code in a project:




Basicly this ends up in the same result like




So is there a real benefit of the first version, and I have no idea?

I think the first ends up in slower code!?
No.

Does a good compiler optimize the first case into the second?
No.

And last but not least, have a look at this:

somePtr t* = new somePtr( );
...
delete t;
t = NULL;

I know, NULL is windows style, but is that necessary?

It's not "windows style". 'NULL' is a macro defined in <cstdlib> (and
possibly other headers) and usually expanding to 0. As for the necessity,
it's up to you. Do you need 't' to be set to null pointer after deleting
the object? Then it does not matter whether you write

t = 0;

or
t = NULL;

except in the latter case you need to include a header that defines the
'NULL' macro.

V
 
T

TB

eiji skrev:
Hi folks,

I found this code in a project:

This creates a new type,
Basicly this ends up in the same result like

and this introduces just another name.
So is there a real benefit of the first version, and I have no idea?

Type constraining.
I think the first ends up in slower code!?
Does a good compiler optimize the first case into the second?

And last but not least, have a look at this:

somePtr t* = new somePtr( );
...
delete t;
t = NULL;

I know, NULL is windows style, but is that necessary?

No, it's not "windows style", NULL is a part of the Standard, and
no, it's not necessary to assign NULL to the pointer after delete.
 
T

Tomás

eiji posted:
Hi folks,

I found this code in a project:


Basicly this ends up in the same result like


So is there a real benefit of the first version, and I have no idea?

Benefit? Depends on what your aim is. However, there's definitely a
difference though:

template<class T>
void SomeFunction(TestList const &); //Defined elsewhere

int main()
{
std::vector<Test> object;

SomeFunction(object); // <---- Will it compile?
}


It _will_ compile if you used "typedef".

It _won't_ compile if you inherited.

somePtr t* = new somePtr( );
...
delete t;
t = NULL;


Typical code from an unambitious (otherwise known as "not overly competent"
programmer). I bet the same person uses "i++" all over the place when "++i"
would suffice.

I wouldn't write such code for fear of being interpreted as mentally
retarded. I'm not retarded enough to mess with a pointer after I've deleted
what it was pointing to. If someone is stupid enough to do that, then Java
is right down their road.

You could fill a warehouse with the disgraceful code that Microsoft write. A
few examples:

1)

#define UINT unsigned int

rather than:

typedef unsigned UINT;

2)

SomePOD object;
ZeroMemory( &object, sizeof(object) );

rather than:

SomePOD object = {};

3)

The list is lloonngg...


-Tomás
 
D

Daniel T.

"eiji said:
Hi folks,

I found this code in a project:


Basicly this ends up in the same result like


So is there a real benefit of the first version, and I have no idea?

The two constructs above are not the same. Try this:

class TestList1 : public vector<int> { /*empty!!!*/ };

typedef std::vector<int> TestList2;

void fn1( const vector<int>& );
void fn2( const TestList1& );
void fn3( const TestList2& );

int main()
{
fn1( TestList1() );
fn3( TestList1() );

fn2( vector<int>() ); // invalid: vector<int> is not substitutable
// for TestList1
fn3( vector<int>() ); // but it is substitutable for a TestList2

fn1( TestList2() ); // TestList2 is substitutable for a vector<int>
fn2( TestList2() ); // invalid: TestList2 is not substitutable
// for TestList1
}

As you can see: vector<int> and TestList2 are the same type as far as
the compiler is concerned but TestList1 is not the same as a
there is only a one way conversion. said:
I think the first ends up in slower code!?

I doubt it.
And last but not least, have a look at this:

somePtr t* = new somePtr( );
...
delete t;
t = NULL;

I know, NULL is windows style, but is that necessary?

It's not "windows style", it is perfectly acceptable C++ code. It
protects you against accidental double deletes, and on many systems, the
OS will recognize an error if you try to dereference a NULL pointer,
where it wouldn't if you didn't NULL the pointer out.

Is it necessary? No, it's never *necessary* to initialize your
variables, but you should still do it.
 
M

Markus Moll

Hi

Tomás said:
Typical code from an unambitious (otherwise known as "not overly
competent" programmer). I bet the same person uses "i++" all over the
place when "++i" would suffice.

I have to disagree.
While I see this kind of code way too often, when it isn't necessary (either
because t will be out of scope right after the assignment, or because you
had better use some smart pointer in the first place), I have to say that
when playing around with raw pointers, it saves you hours of debugging!
Consider:

struct uses_some_pointer
{
int *x; // has to be a pointer for some reason...
uses_some_pointer() : x(0) {}
uses_some_pointer(const uses_some_pointer& usp) : x(new int(*usp.x)) {}
uses_some_pointer& operator= (const uses_some_pointer& usp)
{ delete x; x = new int(*usp.x); return *this; }
~uses_some_pointer() { delete x; }
void f(int a) { delete x; x = new int(a); }
void g() { /* x no longer needed! */ delete x; x = 0; }
};

(where f and g in reality would have other names and would actually do some
work)
I wouldn't write such code for fear of being interpreted as mentally
retarded. I'm not retarded enough to mess with a pointer after I've
deleted what it was pointing to.

Do you really always know? What about exceptions?
Maybe you like memory leaks better?
If someone is stupid enough to do that,
then Java is right down their road.

Java has its own pitfalls...
You could fill a warehouse with the disgraceful code that Microsoft write.

What has Microsoft got to do with that?

Markus
 
T

Tomás

No, it's never *necessary* to initialize your
variables, but you should still do it.


for (int i; i < 10; ++i)
{

}

You've no guarantee that the loop will start at 0.
Futhermore, it's undefined behaviour to check its value.


-Tomás
 
J

Jim Langston

Tomás said:
eiji posted:


Benefit? Depends on what your aim is. However, there's definitely a
difference though:

template<class T>
void SomeFunction(TestList const &); //Defined elsewhere

int main()
{
std::vector<Test> object;

SomeFunction(object); // <---- Will it compile?
}


It _will_ compile if you used "typedef".

It _won't_ compile if you inherited.




Typical code from an unambitious (otherwise known as "not overly
competent"
programmer). I bet the same person uses "i++" all over the place when
"++i"
would suffice.

I wouldn't write such code for fear of being interpreted as mentally
retarded. I'm not retarded enough to mess with a pointer after I've
deleted
what it was pointing to. If someone is stupid enough to do that, then Java
is right down their road.

That point could be argued. Setting a pointer to NULL or 0 after deleting
can have some advantages. The first advantage is if you try to delete a
NULL pointer nothing happens. It's safe to delete a null pointer. The
second advantage is you can compare a pointer to NULL to see if it's been
deleted.

Safely deleting a NULL pointer is not always a good thing, however. Most
the time I find that if I'm attempting to delete a NULL pointer (one that's
already been deleted and set to NULL) then my program is in error.

However, I do have one class that controls GUI windows. Depending on the
type of window it is it can have one or two bitmaps. I found it easiest in
my class to simply set the pointer to NULL if the bitmap was empty. The
code that uses the methods to get the bitmap pointers compare the pointers
to NULL to see if to display or not. Although this is not technically the
same as deleting a pointer than setting it to NULL, it is close. And I can
see a case where I would for some reason delete one of the loaded bitmaps
but keep the other so set it to NULL.
 
K

Kai-Uwe Bux

Markus said:
Hi



I have to disagree.
While I see this kind of code way too often, when it isn't necessary
(either because t will be out of scope right after the assignment, or
because you had better use some smart pointer in the first place), I have
to say that when playing around with raw pointers, it saves you hours of
debugging! Consider:

struct uses_some_pointer
{
int *x; // has to be a pointer for some reason...
uses_some_pointer() : x(0) {}
uses_some_pointer(const uses_some_pointer& usp) : x(new int(*usp.x)) {}
uses_some_pointer& operator= (const uses_some_pointer& usp)
{ delete x; x = new int(*usp.x); return *this; }

Are you sure this handles self-assignment correctly? If you do

a = a;

then the following happens:

a.x is deleted.
A new pointer is allocated and initialized from *(a.x).
Ouch.

~uses_some_pointer() { delete x; }
void f(int a) { delete x; x = new int(a); }
void g() { /* x no longer needed! */ delete x; x = 0; }
};

(where f and g in reality would have other names and would actually do
some work)

Note the also sequences like

a.g();
b = a;

are plain bad. I concede, though, that you *could* have used it in getting
the assignment operator more correct.


[snip]


Best

Kai-Uwe Bux
 
T

Tomás

That point could be argued. Setting a pointer to NULL or 0 after
deleting can have some advantages. The first advantage is if you try
to delete a NULL pointer nothing happens.


Well this shouldn't be done, except if you have a generic function like so:

template<class T>
void DoSomeStuffAndDeleteGivenPointer(T* p)
{
//Suff

delete p; // <-- Okay even if null
}

The above is plausible... but it's just plain stupid if you've something
akin to the following in your code:

{
int* p = new int;

//do some stuff

delete p;
p = 0;

//do some stuff

delete p;
}

It's safe to delete a null pointer. The second advantage is you can
compare a pointer to NULL to see if it's been deleted.

I see the merit in this. It can be used instead of:

delete p;
bool has_been_deleted = false;

//do some stuff

if (has_been_deleted) DoSomeStuff();

Safely deleting a NULL pointer is not always a good thing, however.
Most the time I find that if I'm attempting to delete a NULL pointer
(one that's already been deleted and set to NULL) then my program is in
error.


There's some merit to doing it in Debug Mode. But other than that, it's an
extra superfluous intruction that can only serve to lessen efficiency.

However, I do have one class that controls GUI windows. Depending on
the type of window it is it can have one or two bitmaps. I found it
easiest in my class to simply set the pointer to NULL if the bitmap was
empty.

Not a bad strategy.
The code that uses the methods to get the bitmap pointers compare the
pointers to NULL to see if to display or not. Although this is not
technically the same as deleting a pointer than setting it to NULL, it
is close. And I can see a case where I would for some reason delete
one of the loaded bitmaps but keep the other so set it to NULL.

My overall view is as follows. The following code is just plain retarded:

void SomeFunction()
{
int* p = new int[10];

//do some stuff

delete [] p;

p = 0;
}


However, the following is grand:

void SomeFunction()
{
int* p = new int[10];

//do some stuff

delete [] p;

#ifdef DEBUG
p = 0;
#endif
}


What's the name for the most used macro which indicates if you're in DEBUG
mode? I recall seeing something like NDEBUG. Would it be:

#ifndef NDEBUG
p = 0;
#endif


-Tomás
 
W

werasm

Tomás said:
eiji posted:


Typical code from an unambitious (otherwise known as "not overly competent"
programmer). I bet the same person uses "i++" all over the place when "++i"
would suffice.

Hmmm, setting a deleted pointer to NULL is iaw. the standard. To
emphasize this, I wonder what the authors of auto_ptr do when reset is
called. I cannot imagine them not setting the underlying pointer to
NULL, because reset can be called twice, right? Also, as far as I know
whether one uses ++i or i++, if <i> is a builtin type, it makes no
diffs. I prefer ++i for consistency sake, though. I heard somewhere STL
writers used i++ as their standard (due to legacy), but I may have
heard wrong.
I wouldn't write such code for fear of being interpreted as mentally
retarded. I'm not retarded enough to mess with a pointer after I've deleted
what it was pointing to.

Yes, I'm sure the authors of auto_ptrs are ... retarded :).
If someone is stupid enough to do that, then Java is right down their road.

Seems like the road you should take, as you have this one wrong - just
kidding about the first part. Going from Java to C++ is admittedly
dangerous!
You could fill a warehouse with the disgraceful code that Microsoft write.. A
few examples:

Maybe...

Regards,

W
 
B

Ben Pope

Tomás said:
eiji posted:


I wouldn't write such code for fear of being interpreted as mentally
retarded.

You write plenty of code that gives you that label here :p
I'm not retarded enough to mess with a pointer after I've deleted
what it was pointing to.

Err... why? pointers and the memory they point two are somewhat
different issues. Of course you can reassign a value to the pointer,
after deleting what it was pointing to.
If someone is stupid enough to do that, then Java
is right down their road.

I don't see the relevance of this comment. Java doesn't have pointers.
Not all Java programmers are stupid, and neither are all stupid people
Java programmers. Admittedly the bar to entry is somewhat lower than C++.
You could fill a warehouse with the disgraceful code that Microsoft write. A
few examples:

Microsoft's API is hardly the epitome of current C++ design, but bear in
mind it's age. It pre-dates the C++ standard, I'm sure they'd do it
differently now. They're stuck with it, for compatibility, they are
simply unable to change it now. They're even unable to change things
that were never documented, and even things they explicitly said don't
use. Why? Because MS always gets the blame, even when it's the fault
of the application programmer taking undocumented shortcuts.

Ben Pope
 
N

Neil Cerutti

for (int i; i < 10; ++i)
{

}

You've no guarantee that the loop will start at 0.
Futhermore, it's undefined behaviour to check its value.

int i;
for (i = 0; i < 10; ++i)
{


}
 
N

Neil Cerutti

for (int i; i < 10; ++i)
{

}

You've no guarantee that the loop will start at 0.
Futhermore, it's undefined behaviour to check its value.

Of course, references and const-qualified types are indeed necessary
to initialise.
 
M

Markus Moll

Hi

Kai-Uwe Bux said:
Are you sure this handles self-assignment correctly? If you do

Damn, I knew I would miss something.
You're right, of course.
Note the also sequences like

a.g();
b = a;

Um... yes :)

However, I tried to make a different point...

Markus
 
M

Markus Moll

Hi

Tomás said:
Then put it in the debug code. Something like

#ifdef DEBUG
p = 0;
#endif

This is a lot more work. (Three lines instead of one)
Are you concerned about runtime? (I was not... not with a single assignment
after dynamic memory deallocation)
Plus, if you fail to detect the error while debugging, it might crash later.
Why sacrifice safety and correctness?

Markus
 
W

werasm

The above is plausible... but it's just plain stupid if you've something
akin to the following in your code:

{
int* p = new int;

//do some stuff

delete p;
p = 0;

//do some stuff

delete p;
}

Well, lets take a more elaborate example (I'll keep it brief, but I
realise we need copy constructors etc, so don't crit me on that). This
was typically code to be written before the age of auto_ptr's and
scoped_ptr's.

class XC
{
public:
XC();
~XC();
void doSomethingCausing_A_ToDie();

private:
AC* a_;
BC* b_;
DC* c_;
void Allocate(); //creates dynamically allocated objects
void Cleanup(); //cleans ....
};

XC::XC()
: a_(0), b_(0), c_(0)
{
try
{
Allocate();
}
catch(...)
{
Cleanup();
throw;
}
}
void XC::doSomethingCausing_A_ToDie()
{
delete a_; a_ = 0;
}

XC::~XC()
{
Cleanup();
}
From above example - a couple of things.

1) It was necessary to initialise the members to zero in the beginning.
This way Cleanup could be envoked consistently during failure to
construct, as during destruction.

2) It was necessary to set a_ to 0 after deletion during
doSomethingCausing_A_ToDie(), this way Cleanup still worked correctly
during destruction. No, not only during debugging - always.
However, the following is grand:

void SomeFunction()
{
int* p = new int[10];

//do some stuff

delete [] p;

#ifdef DEBUG
p = 0;
#endif
}

Well, for this example I would rather use:
void foo()
{
int p[10] = {}; //or
std::vector<int> q(10, 0 ); //or
boost::scoped_array<int> r( new int[100] );//or
boost::array<int,10> s = {};
}

.... but I get your point. Actually, in the above case (your example)
setting p to NULL would be worthless, even during debugging. The
example is just not adequate (p is on the stack, why set it to NULL
just prior to the stack vanishing?). However, sometimes it is very
necessary to set p to NULL (in other examples).
What's the name for the most used macro which indicates if you're in DEBUG
mode? I recall seeing something like NDEBUG. Would it be:

Yes, it NDEBUG - used with assert macro.

W
 
T

Tomás

For want of a better word, there's a fair few "stupid" programmers out
there. Thankfully there are also some intelligent, intellectual programmers.

These "stupid" programmers -- if they ever become teachers -- teach people
to always set a pointer to null if the object to which it refers has been
destroyed. Therefore, a "delete" statement must always be accompanied by a
"p = 0;". Such stupidity leads to people writing code like:

int Blah(unsigned k)
{
double* p = new double[k];

//Do some stuff

delete [] p;

p = 0;
}

If you ask one of these "stupid" programmers why they set the variable's
value to zero, then they'll set "because it's good practise".

An intelligent person will say, "That's plain stupid."

In my own humble opinion, it's plain stupid because:

a) It implies that human beings have the intelligence of a squid, and can't
plainly see with their own eyes that "p = 0;" is useless in this particular
example.

b) It's another instruction to execute, and it is superfluous. Executing
superfluous instructions is stupid, but more importantly, it's inefficient.

Many people here always argue against what they call "premature
optimization", or "over-efficiency". They say, "How is it inefficient if it
only adds an extra picosecond to the running time?". My answer is: "Because
it adds an extra picosecond to the running time?".

However... in code samples posted by people here, the "p=0;" statement isn't
pointless, it's used (quite efficiently in fact) as an indicator as to
whether the object has been destroyed. For instance we can replace the
following code:

void Blah()
{
double* p = new double[57];

bool has_been_deleted = false;

//Do some stuff

delete [] p;
bool has_been_deleted = true;

//More stuff

if (has_been_deleted) DoSomething();
}

with:

void Blah()
{
double* p = new double[57];

//Do some stuff

delete [] p;
p = 0;

//More stuff

if ( !p ) DoSomething();
}


This is great.

Overall I'm just against pointless code which insults the intelligence of
the human race. Visual Basic, Java and C# are out there to satisfy the
"stupid programmers"... I just wish they wouldn't pollute the elite realm of
C++ with their kindergarden mickey-mouse "good practise".


-Tomás
 
G

gethostbyname

"Overall I'm just against pointless code which insults the intelligence
of
the human race. Visual Basic, Java and C# are out there to satisfy the
"stupid programmers"... I just wish they wouldn't pollute the elite
realm of
C++ with their kindergarden mickey-mouse "good practise".

-Tomás "

Long Live Thomás! :)

Pedro Henrique
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top