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
quote: Original post by Kippesoep
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.


The point is that the ctor doesn't necessarily do "nothing" as I explained elsewhere. Sure, from the programmer's point of view, they might have an empty ctor. From the compiler's point of view, there is work that has to be done in initialising an object that it will insert into the ctor. The C++ Standard is very explicit that a ctor is *always* present. The discussion has gone on for far longer than it would if people would actually check what the C++ Standard requires.

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

Edited by - SabreMan on February 15, 2002 6:14:37 AM
How about this:

class SomeClass
{
SomeClass() { ... }
};

void fn()
{
SomeClass *pSomeClass = malloc(sizeof(SomeClass));
new SomeClass(pSomeClass);
...
delete pSomeClass;
}

Here, new is called to only construct an object (call ctor, fill vtable, etc.), not to allocate it. It constructs object located at the pointer provided. I''m not sure if this is "legal", but why not? I''m not calling the constructor implicitly (which does not init vtable), rather I''m allocating memory on my own and using C++ way to construct the object.

This is very useful when you want to create classes in memory other than the standard C++ heap, i.e.: you can use HeapCreate() to create a heap for objects of certain type(s), and allocate those objects exclusively from that heap.
---visit #directxdev on afternet <- not just for directx, despite the name
Advertisement
Oh dear.

Sabreman, Anonymous Poster... could you please point out where I said (or even implied!) that default ctors / dtors aren''t created?

I see the claim: "An object''s lifetime has not begun until it''s ctor has been run."

So, what does the default ctor do?

What does a ctor need to do to initialise a class? Does it need to set all the bits in the class instance to zero? I''ve tested that, and it doesn''t happen under any compiler I''ve tried. Does it need to record the existance of the class somewhere? Seeing as c++ has no garbage collector, that wouldn''t be logical. Does it need to initialise the vtable? Only if there actually is a vtable for the class! Does it need to call the constructors for member variables? Sure doesn''t look like it:
  class A {public:    A() { printf("A()\n"); }    ~A() { printf("~A()\n"); }};class B {    A a;public:    B() { printf("B()\n"); }    ~B() { printf("~B()\n"); }};  

When I declare an instance of B, the output is:

A()
B()
~B()
~A()

Looks to me like the member variables are being constructed before the B::B() is called.

I''m also not aware of any requirement that a class has to have member variables. It would be silly not to have them, but as far as I know, it''s valid.

Default ctors / dtors may be created, but so far, it looks to me like they''d be empty.
quote: Original post by smart_idiot
I use malloc()/free() for strings, arrays, and other data of non uniform size, mainly because I learned to use them when I learned c, and I can use realloc() to change their size.

You can use std::string and std::vector for this purpose in C++.

I mostly agree with ''a person''''s assement of ctor&dtor calls. They are based upon empirical observation, which is always more reliable than theory or specifications.

In theory, a ctor is always called prior to object lifetime. In practice, if no code need to executed at this time, the ctor effectively doesn''t exist.

The basic default ctor does nothing. But all default ctor''s do not do nothing - imagine we have enabled RTTI. Code in the ctor must execute to fill-in the requesite information. However, MSVC6 will even optimize out RTTI calls on non-polymorphic classes, replacing them with static infomation.

The default ctor *will* call constuctors for members (if there are any), if those ctors bake away to nothing, then so will the parent ctor. So while in compiler theory it exist (the compiler did have to do work here), in the code there is no trace of it.


...
IndirectX, you''re creating a new SomeClass on the heap by invoking the default copy constructor, leaking the memory allocated by new, and corrupting the heap by calling delete on memory acquired by malloc. MSVC6 in debug mode should complain loudly about this.

You can do what you describe, it''s called ''placement new'', and is an STL overload.
  #include <new> void* pv = malloc(sizeof(SomeClass));SomeClass* pSomeClass = new(pv) SomeClass; //placement new//...pSomeClass->~SomeClass(); //explicitly invoke the dtorfree(pSomeClass); //you used malloc, remember!  


Magmai Kai Holmlor

"Oh, like you''ve never written buggy code" - Lee
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
You''re right. Sorry about that.
---visit #directxdev on afternet <- not just for directx, despite the name
actually that behavior is PERFECTLY sensible, and i would be angry if it failed. two reasons:

1. C++ standard implies that a class is just a struct with private as its default scope. making class and struct not affect whether the array of data is an object or an area of data. since c++ is supposed to be somewhat backwards compatible with C.

2. according to the C++ standard, member functions that are not virtual are created staticly and called like normal functions with an added this parm. thus as long as the function is not virtual NO look up is required by the compiler so it can be handled at compile time instead of runtime.



example:

  // C codestruct blah{   int x, y;};int blah_function(stuct blah* THIS){   printf("\n%d %d", THIS->x, THIS->y);   return 0;}// would equal this in c++// C codestruct blah{   int x, y;   function();};int blah::funtion(){   printf("\n%d %d", x, y);   return 0;}  


notice an similarities or other wierd things? like how its the same concept. classes where just an extension of structs by ALLOWING an implicitly called constructor and deconstror. if you dont require one, why should the compiler add the overhead of creating and calling one? makes no sense at all. furthermore, if you bother to check the disassembly you will notice the only difference between new and malloc is the function call to grab the memory. the "new" keyword prompts the compiler to insert a constructor/deconstructor and handle vtable stuff if needed. the actually call to "new" never does this at all.

furthermore please explain the difference in the following code, assuming that the standard makes exceptions based on atomic types like ints.

  struct intStruct{   int x, y, z;};class intClass{public:   int x, y, z;};int intArray[3];  


from what you say the struct and class get constructors but the array does not. which makes me wonder, how reliable the standard is if you have stupid exceptions that make no sense. since in reality to the compiler all those are EXACTLY the same. granted access in the code will be slightly different since you have names for each of the members for the struct/class and not the array.

btw all the information was gathered from mulitple compiles of code and viewing the disassembly. whether its the standrd or not, really dont matter if its not implemented by compilers (especially popular ones like msvc++ AND gcc).

just for some more "nuggets" of information. gcc does not allow one to define a fucntion in a struct/class without a return type, since thats against the ansi c++ standard. msvc++ goes around this by assuming an int return type. yet gcc nor msvc care about the mallocing of a class and then calling the function. nor do they crash and burn. likewise i HIGHLY doubt that optimizations would EVER intefere with this. because if the compiler optimizes out the constructor and deconstructor whne NO optimizations are set and you are using debug which strives for easy debugging and not speed. i am pretty sure an optimizer wont screw that code up more (since you cant unless there is a MAJOR bug in the compiler, but then most function calls where you pass pointers would not work).

Saberman, i think where you are getting confused is by the fact that the ansi c++ standard allows c backwards combatiblity to a point. which REQUIRES that the behavior i have presented to you must exist. in fact ALL c++ code can be converted to c code (you probably know this), and it would be midly retarded to have implicit constructors in the c version for any struct that had no use for them.

the funniest thing you said though was how copying the .exe to another pc will somehow affect how its run. i dont quite understand how working compiled code will break on another system unless there is a hardware compatiblity issue, system file differences (ie different version of OS), or bad software that is running on the pc (ie 3rd party software that is buggy).

thankfully ppl like Magamei see my point, which is just because the standard says something, dont mean in reality thats how things work. the standard merely gives you a suggestion on how to implement things and how things should work in THEORY. in practice the compiler is free to make optimizations as long as it does not break code.
Advertisement
I was going to let this thread die, as I think it''s gone on too long and is not adding anything of particular value. However, you made some points that I feel compelled to respond to...

quote: Original post by a person
Saberman, i think where you are getting confused is by the fact that the ansi c++ standard allows c backwards combatiblity to a point. which REQUIRES that the behavior i have presented to you must exist. in fact ALL c++ code can be converted to c code (you probably know this), and it would be midly retarded to have implicit constructors in the c version for any struct that had no use for them.


I am not at all confused. I have understood this issue as it is specified by the Standard since the Standard was ratified. I have had read the opinions of world class C++ experts on the topic. Scott Meyers is one such expert, and you can read what he has to say on the topic in his book Effective C++.

quote:
the funniest thing you said though was how copying the .exe to another pc will somehow affect how its run. i dont quite understand how working compiled code will break on another system unless there is a hardware compatiblity issue, system file differences (ie different version of OS), or bad software that is running on the pc (ie 3rd party software that is buggy).


You are quite clearly unfamiliar with the concept of undefined behaviour. Again, Scott Meyers came up with a good description of this: "it works when you debug it, it works when you release it to product test, and then it blows up during a customer demo". There is nothing funny about what I said, it''s happened to me. I''ve learnt from the experience.

quote:
thankfully ppl like Magamei see my point, which is just because the standard says something, dont mean in reality thats how things work. the standard merely gives you a suggestion on how to implement things and how things should work in THEORY. in practice the compiler is free to make optimizations as long as it does not break code.


Yes, Magmai is obviously very knowledgeable. However, the standard does not "give a suggestion on how to implement things". It *specifies* how C++ must work. You''re right about the compiler making optimisations that do not break the semantics of the code but, semantically speaking, an object always has a ctor and dtor. Even if the ctor and dtor do nothing.

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

This topic is closed to new replies.

Advertisement