views:

562

answers:

7

Hello

Can I call constructor explicitly, without using new, if I already have a memory for object?

class Object1{
    char *str;
public:
    Object1(char*str1){
        str=strdup(str1);
        puts("ctor");
        puts(str);
    }
    ~Object1(){
        puts("dtor");
        puts(str);
        free(str);
    }
};

Object1 ooo[2] = {
     Object1("I'm the first object"), Object1("I'm the 2nd")
};

do_smth_useful(ooo);
ooo[0].~Object1(); // call destructor
ooo[0].Object1("I'm the 3rd object in place of first"); // ???? - reuse memory
+22  A: 

Sort of. You can use placement new to run the constructor using already-allocated memory:

 #include <new>

 Object1 ooo[2] = {Object1("I'm the first object"), Object1("I'm the 2nd")};
 do_smth_useful(ooo);
 ooo[0].~Object1(); // call destructor

 new (&ooo[0]) Object1("I'm the 3rd object in place of first");

So, you're still using the new keyword, but no memory allocation takes place.

unwind
Yes, the direct destructor call is in fact necessary to allow the object to release any resources, before overwriting the object with a newly constructed object.
Will
Yeah, I updated the sample. The Object1 constructor calls strdup and destructor must to `free(str)`.
osgx
destructor call is allowed. C++98: [class.dtor] paragraph 13:`X*p; ... p->X::~X();`
osgx
+1 - though strictly speaking, "placement new" isn't exactly "without new" ;-)
Steve314
@Steve314: I know, that's why I pointed out that the keyword is still there, but no allocation is taking place.
unwind
There should not be a big "Yes" on the top, It is misleading
Yogesh Arora
Also, beware that disaster will strike if the constructor throws. The object will be left uninitialised, but the destructor will still be called at some point in the future.
Mike Seymour
A: 

You can call a destructor, but memory will not be reclaimed, and your call will be equivalent to a function call. You have to remember that underneath the destructor does 2 things: destructs object based on your specification, and reclaims the memory. Since you dtor will be called anyway for an object allocated on the stack, calling it twice may result in an undefined behavior.

vehomzzz
Au contraire, if `Object1` holds pointers to things that need to be `delete`d, the explicit destructor call will ensure that happens, before overwriting the object with a newly constructed object. Then the automatic stack destructor call will destruct the newly constructed object, so you're not calling it twice on the same object.
Will
but in my sample code, I create 2 Object1 in initializer, then destruct the first and recreate (reconstruct) in place of the 1st the 3rd object. When this block is closed, `ooo[2]` will call two destructors. So this sample is normal?Does destructor reclaims memory by itself, or only when used with delete or implicit 'delete' when stack is shrinked?
osgx
The destructor doesn't reclaim the memory of the object being destroyed, but it sure can call delete (or delete[], or free, or HeapFree, etc) on additional memory that object had owned. It's that related memory that would be reclaimed when the destructor runs.
Ben Voigt
A: 

Yes, when you've got your own allocated buffer you use placement new. Brian Bondy has a good response here in a related question:

http://stackoverflow.com/questions/222557/cs-placement-new

itsmatt
+7  A: 

I think you're looking for Placement New. The C++ FAQ Lite has a good summary of how you do this. There are a few important gotchas from this entry:

  1. You're supposed to #include <new> to use the placement new syntax.
  2. Your memory buffer needs to be properly aligned for the object you are creating.
  3. It's your job to manually call the destructor.
Kristo
You have to `#include` a library just to use some C++ syntax? I'm not contradicting you - I just think this is really wierd.
Steve314
@Steve314: The C++ syntax is giving arguments to `new`, which are passed through to a matching overload of `operator new`. You need the library to provide the required overload, `operator new(size_t,void*)`.
Mike Seymour
I'm not aware of a need to call `operator new` - I already have the memory allocated, and I thought the placement new was just calling the constructor. I've certainly been getting away without worrying about this, though (1) it's possible I have included `<new>` somewhere, and (2) it's always possible that my compiler is letting me get away with something naughty. Time to review things, I guess, and see if I'm doing something wrong.
Steve314
It calls a replacement operator new which is defined for you in the standard library which doesn't allocate any memory, it just returns the memory you passed into it. Then the constructor is called as usual, thus achieving what you wanted. it's not really syntax, it's a redefined operator new that basically just returns it's extra paramater
John Burton
A: 

Yes, using placement new - as above, but you might consider having a second factory class to manage the storage, even if it means copying an object. memcpy() is generally cheap for small objects.

Martin Beckett
Can I really do a memcpy for object? I want to write rather universal container, like STL vector. Some objects can depend on its address (store inside itself address)
osgx
+2  A: 

Literally speaking, NO, you can't do it without the "new" keyword. See all the answers about placement new for the way to use the "new" keyword to call the constructor without actually allocating memory.

Ben Voigt
+2  A: 

Let me show you some code on how it can be done, both in construction and destruction

#include <new>

// Let's create some memory where we will construct the object.
MyObject* obj = (MyObject*)malloc(sizeof(MyObject));

// Let's construct the object using the placement new
new(obj) MyObject();

// Let's destruct it now
obj->~MyObject();

// Let's release the memory we used before
free(obj);
obj = 0;

I hope the above summary makes things clearer.

Cthutu