有没有办法使用 placement new 将堆叠对象分配给分配的内存?

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

这是我的程序:

#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;
}

在存储中,我分配 space 来存储一个 Object 类型的对象而不创建它。我正在使用 placement new 来分配内存,并在析构函数中释放它。我知道我可以使用

object = new(object) Object()

构造对象。但是我可以在内存中放入一个已经创建的对象吗?在我的例子中调用方法 setObject()。如果是的话,这样的内存管理会遇到什么问题?提前致谢。

实现您尝试实现的行为的最简单方法是使用 C++17 中的 std::optional。它将允许您 "reserve" 您的 Object 内存而无需构建它,并且 无需使用堆 。它还将处理所有构造函数和析构函数调用。

这也可以在没有 std::optional 的情况下完成,但您基本上必须自己实施类似的解决方案。在任何情况下,您都需要一个额外的成员来指定对象是否构造,以便您可以正确处理销毁和赋值。

那么您的 setObject 方法将如下所示:

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

要使用移动语义,您可以像这样修改您的方法:

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

请注意,现在 setObject 按值接受它的参数,因此它可以与左值和右值引用一起使用来构造参数,然后将其移入成员中。

Placement new 是一个非常高级的构造,拥有一个实际上指向未初始化内存的 Object* 的想法是相当可怕的。我可以建议你让你的生活更轻松吗?

class Storage {
    void setObject(const Object& obj) {
        if (object) {
            *object = obj;
        } else {
            object.reset(new Object(obj));
        }
    }
private:
    std::unique_ptr<Object> object;
};

这需要 Object class 上的复制构造函数和赋值运算符,但更符合 C++ 的习惯用法。在如图所示的 Object 实现中,编译器提供的默认实现已经很好了。

澄清一下:

But can I put in the memory an object that is already created?

不,你不能。在 C++ 中无法移动内存中的对象。对于 普通可复制 类型,您可以复制(例如,通过 memcpymemmove)它们的内存表示。但这实际上并没有移动任何东西。此外,您的 Object class 不可简单复制。

您可以移动的是对象的内容,这就是移动语义的用途。