Search code examples
c++c++11referenceplacement-new

Is there a way to assign a stacked object to the allocated memory using placement new?


Here is my program:

#include <iostream>

using namespace std;

class Object {
public:
    Object() { cout << "Object constructor!" << endl; }
    ~Object() { cout << "Object destructor!" << endl; }
    Object(const Object& obj) { information = obj.information; cout << "Copy constructor!" << endl; }
    void setInformation(const string info) { information = info; }
    string getInformation() const { return information; }
private:
    string information;
};

class Storage {
public:
    Storage() { object = static_cast<Object*>(operator new(sizeof(Object))); }
    ~Storage() { operator delete(object); }

    void setObject(const Object& obj) {
        // Todo: assign obj to the allocated space of the pointer object
    }
private:
    Object* object;
};

int main()
{
    Object o;
    o.setInformation("Engine");
    Storage storage;
    storage.setObject(o);
    return 0;
}

In Storage I am allocating space to store one object of type Object without creating it. I am using placement new for that which allocates a memory, and freeing it in the destructor. I know that I can use

object = new(object) Object()

to construct an object. But can I put in the memory an object that is already created? In my case call method setObject(). If yes what problems I can encounter with such memory management? Thanks in advance.


Solution

  • The simplest way to achieve the behavior you are trying to implement would be to use std::optional from C++17. It will allow you to "reserve" the memory for your Object without constructing it and without using the heap. It will also handle all the constructor and destructor calls.

    This also can be done without std::optional, but you will essentially have to implement a similar solution yourself. In any case you will need an additional member to specify whether object constructed or not, so you can properly handle the destruction and assignment.

    Then your setObject method will look something like this:

    void setObject(const Object& obj) {
        if (constructed) {
            *object = obj;
        } else {
            new (object) Object(obj);
            constructed = true;
        }
    }
    

    To make use of move semantics you can modify your method like this:

    void setObject(Object obj) {
        if (constructed) {
            *object = std::move(obj);
        } else {
            new (object) Object(std::move(obj));
            constructed = true;
        }
    }
    

    Note that now setObject accepts it parameter by-value so it can be used with both lvalue and rvalue references to construct the parameter which is then will be moved into the member.