Advertisement

C/C++ new and delete vs. malloc and free

Started by February 12, 2002 09:18 AM
25 comments, last by Fundy Glostna 22 years, 10 months ago
I haven''t noticed anyone state the obvious here, so here goes.
In C++, a struct *is a* class. Internally, the compiler regards them both as the same thing, albeit with different default access modifiers: public for struct, private for class. So, yes you can create a struct using new, and that would be the recommended means of doing so. Note also that structs (and classes) *always* have constructors and destructors. If you don''t provide one, the compiler inserts a default for you.
quote: Note also that structs (and classes) *always* have constructors and destructors. If you don''t provide one, the compiler inserts a default for you.


I don''t see why it would. If you don''t provide a constructor, no constructor is called. If you don''t provide a deconstructor, no deconstructor is called. The memory is still allocated and deleted but no functions are called. At least, I can''t imagine why the compiler would generate code to call a function that it knows does nothing.

~CGameProgrammer( );

~CGameProgrammer( ); Developer Image Exchange -- New Features: Upload screenshots of your games (size is unlimited) and upload the game itself (up to 10MB). Free. No registration needed.
Advertisement
quote: Original post by CGameProgrammer
I don''t see why it would. If you don''t provide a constructor, no constructor is called. If you don''t provide a deconstructor, no deconstructor is called. The memory is still allocated and deleted but no functions are called. At least, I can''t imagine why the compiler would generate code to call a function that it knows does nothing.


A ctor and dtor are *always* called when an object is created and destroyed, respectively. No exceptions to that rule. An object''s lifetime has not begun until it''s ctor has been run.

Strictly speaking, the ctor and dtor are not functions, they are code blocks associated with a class for lifetime management. The default ctor and dtor do not "do nothing", it''s just that you can''t see what they do because it goes on under the hood.
Sabreman - So what do the default ctor and dtor do? You''re not going to be taken seriously if there''s no substance to your argument.
quote: Original post by Beer Hunter
Sabreman - So what do the default ctor and dtor do? You''re not going to be taken seriously if there''s no substance to your argument.


The precise details are compiler-specific, but there needs to be somewhere that a class''s bases and members are initialised / uninitialised. Compiler implementors will often use the ctor / dtor as a placeholder for inserting the code to do this. The "this" pointer also needs to be set up, and the ctor is a good place to do so.

If you don''t wish to take my word for it that a default ctor and dtor will be added to your class, then check the Standard.
quote: Original post by Beer Hunter
Sabreman - So what do the default ctor and dtor do? You''re not going to be taken seriously if there''s no substance to your argument.

And you''re not going to be taken seriously if you question something that anyone who actually learned about C++ already knows.
Advertisement
From the Standard...

[12.1 Constructors]

"A default constructor for a class X is a constructor of class X that can be called without an argument. If there is no user-declared constructor for class X, a default constructor is implicitly declared."

...and...

"An implicitly-declared default constructor for a class is implicitly defined when it is used to create an object of its class type."
funny, checking the disassembly, msvc++ does not add ANY constructor deconstructor at all. in fact it does not call a constructor or deconstructor, unless its invisible and optimized out by the debug optimizer that the disassembly wont show it.

what does this mean?

1. for basic types like ints, floats, doubles, chars, etc. no contrsuctor or deconstructor blocks of code are added at all by the compiler.

2. structs/classes that dont explicitly define a constructor dont get one at all. same with deconstrutor. well at least the compiler dont call nor add it to the struct.

3. funtions not that are not virtual and part of the struct/class are NOT stored with the class/struct. instead they are called directly with the correct parms (this, etc).

4. the ONLY time a struct/class gets a (de)constructor funtion is:
a. if the struct/class has explicitly defined a constructor/deconstructor.
b. if there is a virtual funcion in the class/struct, then the compiler creates the vtable and (de)construcors if not defined.
c. if a class/struct inhereits a virtual function.

the following code is VALID and works perfectly well in msvc++ and i am sure most compilers.

  class blah_c{public:	hello(){printf("\nhello %d, %d", x, y);};	int x, y;};class blah_c2 : public blah_c{public:	int z;};int main(){	blah_c2 *c;	c = (blah_c2*)malloc(sizeof(blah_c2));	c->x=10; c->y=20;	c->hello();	free(c);	return 0;}  


so basically it boils down to, if there is no need for a (de)constructor it is not added by the compiler (even in debug mode). standards ussually are best practice to follow, but in reality, do you expect a constructor for an array of ints? maybe next time yu actualy check what the compiler "inserts for you" before saying what it dges.

though i suggest NEVER creating classes using malloc, and always use#new. because the second you add that virtual function your screwed.

oh, as you may have guessed. malloc does not call the constructor nor fill the vtable.
What exactly is the point of this entire discussion. I would think that it''s pretty obvious that if a constructor for an object basically boils down to nothing (you could consider that being the case for standard types, as if it were:
int::int () {} 

) that the compiler would completely omit the function call, especially as its implicitly declared as doing nothing.
There is one obvious example in which you can see an implicit constructor/destructor at work, though:
  class A{  A () { cout << "A::A()"; }  ~A () { cout << "A::~A()"; }}class B{  //B has no explicit ctor/dtor  //Have an instance of A  A m_a;}B *b = new B;delete b;  


B''s implicit constructor will create m_a. BTW, this implicit ctor will appear before your own even if you define one.

Kippesoep
quote: Original post by a person
funny, checking the disassembly, msvc++ does not add ANY constructor deconstructor at all. in fact it does not call a constructor or deconstructor, unless its invisible and optimized out by the debug optimizer that the disassembly wont show it.


I'd hardly consider MS as the final arbiter of what is considered correct in C++.

quote:

what does this mean?

1. for basic types like ints, floats, doubles, chars, etc. no contrsuctor or deconstructor blocks of code are added at all by the compiler.

2. structs/classes that dont explicitly define a constructor dont get one at all. same with deconstrutor. well at least the compiler dont call nor add it to the struct.

3. funtions not that are not virtual and part of the struct/class are NOT stored with the class/struct. instead they are called directly with the correct parms (this, etc).

4. the ONLY time a struct/class gets a (de)constructor funtion is:
a. if the struct/class has explicitly defined a constructor/deconstructor.
b. if there is a virtual funcion in the class/struct, then the compiler creates the vtable and (de)construcors if not defined.
c. if a class/struct inhereits a virtual function.


Where did you get this information from? Not that I'm saying it's wrong, just that it's certainly not talking about Standard C++, which is what I was talking about.

quote:
the following code is VALID and works perfectly well in msvc++ and i am sure most compilers.

        class blah_c{public:	hello(){printf("\nhello %d, %d", x, y);};	int x, y;};class blah_c2 : public blah_c{public:	int z;};int main(){	blah_c2 *c;	c = (blah_c2*)malloc(sizeof(blah_c2));	c->x=10; c->y=20;	c->hello();	free(c);	return 0;}        



That code is completely illegal by the C++ Standard. An object's lifetime does not begin until after it's ctor has been run. Any attempt to access it (outside of certain provisos which don't apply to your example) results in undefined behaviour. Many people trip up on undefined behaviour, since it can apparently do something fairly sensible. That doesn't mean the apparently sensible behaviour is always reproducible. For example, if you are invoking undefined behaviour, then your program might run perfectly fine when you debug it, even when you do a release build. You might then copy the .exe to another PC for a customer demo, and everything falls flat on it's face. Cue many hours of "hunt the bug".

quote:
so basically it boils down to, if there is no need for a (de)constructor it is not added by the compiler (even in debug mode). standards ussually are best practice to follow, but in reality, do you expect a constructor for an array of ints?


An int does semantically have a constructor, although being a built-in type, it's a special case. We were talking about user-defined classes.

quote:
maybe next time yu actualy check what the compiler "inserts for you" before saying what it dges.


The compiler that I use does not determine what is correct. That's what the Standard is for. My job requires me to be aware of that, and it's often important to me. If you want to disregard correctness, that's your choice.

quote:
though i suggest NEVER creating classes using malloc, and always use#new. because the second you add that virtual function your screwed.


You can create classes using malloc if you want a custom allocation scheme, but you need to ensure class alignment requirements are satisfied and you still need to run the ctor by use of placement new.

quote:
oh, as you may have guessed. malloc does not call the constructor nor fill the vtable.


Thanks for that nugget.



--
Very simple ideas lie within the reach only of complex minds.

Edited by - SabreMan on February 15, 2002 9:02:36 AM

This topic is closed to new replies.

Advertisement