有没有办法使用 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++ 中无法移动内存中的对象。对于 普通可复制 类型,您可以复制(例如,通过 memcpy
或 memmove
)它们的内存表示。但这实际上并没有移动任何东西。此外,您的 Object
class 不可简单复制。
您可以移动的是对象的内容,这就是移动语义的用途。
这是我的程序:
#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++ 中无法移动内存中的对象。对于 普通可复制 类型,您可以复制(例如,通过 memcpy
或 memmove
)它们的内存表示。但这实际上并没有移动任何东西。此外,您的 Object
class 不可简单复制。
您可以移动的是对象的内容,这就是移动语义的用途。