61

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
osgx
  • 90,338
  • 53
  • 357
  • 513
  • 2
    Oh yeah, this seems interesting. I'd answer that it is not possible but I'd better wait before making a fool of myself. I'm def faving this. – Anzurio Mar 22 '10 at 17:46
  • dup: http://stackoverflow.com/questions/313882/can-you-invoke-an-instantiated-objects-class-constructor-explicity-in-c and http://stackoverflow.com/questions/1124634/c-call-destructor-and-then-constructor-resetting-an-object – Potatoswatter Mar 22 '10 at 18:45
  • 1
    short answer is No, long answer is there is a way by which memory reuse can be achieved, its called placment new. But keep in that placement new has uses other than reusing memory. – Yogesh Arora Mar 22 '10 at 19:06
  • 3
    Is there a reason you don't just create an assignment operator? – Dennis Zickefoose Mar 22 '10 at 19:13
  • 1
    @Dennis Zickefoose, yes. deleting and reconstructing is in different methods – osgx Mar 22 '10 at 22:05
  • @osgx: even so, before using placement new you should fully understand the "rule of three" in C++, and appreciate all the errors you can make when you introduce an unusual object lifecycle. Your class as written is a likely source of double-free errors. If you want to free the memory early, then instead of calling the destructor you could define a function "release()". Call that after `do_smth_useful`, perhaps also call it from the destructor, and then use `operator=` or a "set" function for the new value. – Steve Jessop Mar 22 '10 at 23:00
  • 2
    So call those methods from the asignment operator. That is the correct way to deal with assignment. – Dennis Zickefoose Mar 22 '10 at 23:01
  • 1
    @Dennis: copy-and-swap is the correct way to deal with assignment :-). So yes, call those functions from the assignment operator, but not in the most obvious way. – Steve Jessop Mar 22 '10 at 23:04
  • no-no-no. I want to make an STL-like container (for learning and with only very basic functionality). This container will store Objects (any object, just like STL) in array, allow me to add and to remove them. – osgx Mar 23 '10 at 00:13
  • @osgx: OK, so `Object1` is actually going to a template parameter, and it's not your container's fault that it's broken. In that case I withdraw my objection to using placement new, Your Honour, but it should still be noted for the record that `Object1 o; mycontainer.push_back(o);` will result in undefined behaviour sooner or later. – Steve Jessop Mar 23 '10 at 00:30
  • @Steve Jessop, i will need to destruct object only in `void pop()`, when deleting object from container. As I want to use array of objects (not pointer) to be stored in container, I will need to destruct one, but not use delete for it. – osgx Mar 23 '10 at 02:12
  • @Steve Jessop, http://stackoverflow.com/questions/2096571/how-is-c-stl-vector-implemented answer from Jan 19 at 20:52 UncleBens. He says, that stl vector does use THE SANE TECHNIQUE with placement new and direct calls to ~T() – osgx Mar 23 '10 at 02:16
  • Yes, the problem is in the class `Object1`, not in the placement new technique. Its copy constructor and assignment operator result in two objects sharing the same `malloc` ed buffer. You should either implement them, or else declare them private member functions (and not define them). – Steve Jessop Mar 23 '10 at 11:37

9 Answers9

86

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
  • 391,730
  • 64
  • 469
  • 606
  • 3
    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 Mar 22 '10 at 17:50
  • Yeah, I updated the sample. The Object1 constructor calls strdup and destructor must to `free(str)`. – osgx Mar 22 '10 at 18:00
  • destructor call is allowed. C++98: [class.dtor] paragraph 13: `X*p; ... p->X::~X();` – osgx Mar 22 '10 at 18:07
  • 1
    +1 - though strictly speaking, "placement new" isn't exactly "without new" ;-) –  Mar 22 '10 at 18:23
  • 1
    @Steve314: I know, that's why I pointed out that the keyword is still there, but no allocation is taking place. – unwind Mar 22 '10 at 18:47
  • 2
    There should not be a big "Yes" on the top, It is misleading – Yogesh Arora Mar 22 '10 at 18:52
  • 11
    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 Mar 22 '10 at 19:14
20

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
  • 8,713
  • 7
  • 33
  • 49
17

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.
Michael Kristofik
  • 34,290
  • 15
  • 75
  • 125
  • 1
    You have to `#include` a library just to use some C++ syntax? I'm not contradicting you - I just think this is really wierd. –  Mar 22 '10 at 18:25
  • 6
    @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 Mar 22 '10 at 18:38
  • 2
    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 `` 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. –  Mar 22 '10 at 18:52
  • 2
    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 – jcoder Mar 22 '10 at 19:21
6

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
  • 277,958
  • 43
  • 419
  • 720
  • Anyone know the relevant section of the spec that defines this? – nmr Oct 10 '15 at 18:52
  • @nmr: Did you mean the section that shows that placement new does do it, or the section(s) that show that the constructor can't be re-called in other ways explicitly in any other way. – Ben Voigt Oct 10 '15 at 18:54
  • the latter -- that constructors can't be called directly. – nmr Oct 11 '15 at 17:02
  • @JaveneCPPMcGowan: Libraries use placement new. Only the compiler itself can call the constructor without placement new. – Ben Voigt Jun 15 '19 at 11:34
  • @Ben Voigt I made the comment because I got the understanding that I needed to include new to use placement new. I want to verify, you dont need to include new to use that syntax. However, it is sad we must use a syntax I never heard about, instead of obj.std::string() for example. I dont see why ctors dont have a name, and why c++ have to be so complicated and full of syntax. –  Jun 16 '19 at 14:32
  • @JaveneCPPMcGowan: If constructors had a name, you could take their address and later call them through a function pointer. On any line `obj.*pmf()` you couldn't tell if it were a constructor call (killing the old object by reusing it) or not. By making constructor invocation a unique syntax it separates it from ordinary function call. There are many many rules that give constructors different semantic behavior from other function calls, so different syntax strengthens the semantics instead of confusing them. – Ben Voigt Jun 16 '19 at 19:37
  • @Ben Voigt I think you have to do better than that. trying to call a member/name of an object via (.)operator/ (->) operator/ (.*) operator/ (->*) operator is a static compile time operation. Meaning you know exactly the type of the object before compilation, and you cannot use names from an object that is not a member of the object. In short, it is clear that you are calling a constructor. –  Jun 16 '19 at 21:25
  • @JaveneCPPMcGowan: You would know it is a member; you would not know it is a constructor. – Ben Voigt Jun 16 '19 at 21:29
  • @JaveneCPPMcGowan: Because once you create a function pointer, you no longer know the name of what it points to... – Ben Voigt Jun 17 '19 at 00:05
  • @Ben Voigt I am sure you meant object pointer. As I said, the information is right there. std::string *s; s->vector() is clearly wrong. If you talking about dynamic type, I only care about static type here. Programmer would be responsible to handle runtime type and cast appropriately. –  Jun 17 '19 at 08:22
  • @JaveneCPPMcGowan: You are wrong, I meant function pointer. That is why you are not understanding my example of `obj.*pmf()` which uses a pointer-to-member-function. You are thinking about indirection to the object, and I am thinking about indirection to the function. If a constructor could be invoked indirectly interchangeably with any other member function, reasoning about object lifetime in the presence of member function pointers would be a lot harder than it is now. – Ben Voigt Jun 17 '19 at 14:13
  • I dont think ctor is really concerned with lifetime of object. It is a function designed to set data members in a valid state and create any necessary resources. For example, new calls ALLOCATES memory but also calls the ctor for us. But if we dont call delete, the lifetime of the object is indefinite. point: ctor has nothing to do with the lifetime of an object. –  Jun 18 '19 at 01:06
  • @JaveneCPPMcGowan: Here, object lifetime rules. Notice the many mentions of "construction": http://eel.is/c++draft/basic.life – Ben Voigt Jun 18 '19 at 05:22
  • Quoted from your link when lifetime of object ends: if T is a non-class type, the object is destroyed, or (1.4) if T is a class type, the destructor call starts, or (1.5) the storage which the object occupies is released, or is reused by an object that is not nested within o ([intro.object]). –  Jun 18 '19 at 23:35
  • @JaveneCPPMcGowan: Yes, constructing a new object hits that "reused by an object that is not nested within...." case. Calling a constructor (other than a delegating constructor, in which case only one of the constructor calls counts) constructs a new object. The lifetime of the one that previously occupied the same storage immediately ends. – Ben Voigt Jun 19 '19 at 00:42
  • @Ben Voigt I was unable to compile your paragraph. Syntax not parsable. –  Jun 19 '19 at 01:59
2

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

What uses are there for "placement new"?

Community
  • 1
  • 1
itsmatt
  • 31,265
  • 10
  • 100
  • 164
1

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
  • 42,832
  • 72
  • 186
  • 216
  • 1
    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 Mar 22 '10 at 17:53
  • 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 Mar 22 '10 at 17:56
  • 2
    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 Mar 22 '10 at 17:59
1

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
  • 94,801
  • 28
  • 188
  • 263
  • 1
    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 Mar 22 '10 at 18:37
0

You can use the following template

template <typename T, typename... Args>
inline void InitClass(T &t, Args... args)
{
    t.~T();
    new (&t) T(args...);
}

usage:

struct A
{
   A() {}
   A(int i) : a(i) {}
   int a;
} my_value;

InitClass(my_value);
InitClass(my_value, 5);
-3

Based on comments, this only works for Microsoft C++ compilers

Quite simply, without new:

    imguistate = (int *)malloc(ImGui::GetInternalStateSize());
    memset(imguistate, 0, ImGui::GetInternalStateSize());
    ((ImGuiState *)imguistate)->ImGuiState::ImGuiState();

This works with any class:

class SomeClass {
public:
    SomeClass() {
        printf("Called constructor\n");
    }
};

int main () {
    SomeClass *someclass = new SomeClass;
    someclass->SomeClass::SomeClass(); // call constructor again
}
kungfooman
  • 4,473
  • 1
  • 44
  • 33
  • What is ImGuiState::ImGuiState()? Will this work for any class? – osgx Aug 05 '16 at 14:11
  • Yes, it works with any class, extended answer with custom class. – kungfooman Aug 06 '16 at 22:15
  • 1
    No, it doesn't work in C++ (do read first word of question title, parse it with all punctuation). gcc (g++) says "`error: cannot call constructor 'SomeClass::SomeClass' directly`". clang++ says "`error: cannot refer to type member 'SomeClass' in 'SomeClass' with '->'`". What is wrong with your compiler, is it Microsoft's ManagedC++? Does it have any standard or something which may resemble anything like standdard compliance? – osgx Aug 07 '16 at 06:36
  • @osgx I'm using Microsoft Visual Studio 2015 Community Edition (unmanaged C++). Thanks for the info, did not know that it won't work in gcc/clang. – kungfooman Aug 07 '16 at 22:50
  • 1
    Seems undocumented: https://msdn.microsoft.com/en-us/library/hh567368.aspx / https://msdn.microsoft.com/en-us/library/34h23df8.aspx. Try `/Za`, `/Ze`, [`/Zc`](https://msdn.microsoft.com/en-us/library/w455da8a.aspx) options – osgx Aug 07 '16 at 23:08