当前实施
我有一个包含unique_ptr
相互依赖的字段的类:
class ResourceManager {
ResourceManager() {}
ResourceManager(A* a_ptr) :
b_ptr(new B(a)),
c_ptr(new C(b_ptr.get())) {}
ResourceManager& operator=(ResourceManager&& that) {
// Call destructor, then construct a new instance on top
~ResourceManager();
ResourceManager* new_this = new(this) ResourceManager();
// Surely this must be the case, right?
// Is there any reason to prefer using either?
assert(new_this == this);
new_this->b_ptr = that.b_ptr;
new_this->c_ptr = that.c_ptr;
return *new_this;
}
unique_ptr<B> b;
unique_ptr<C> c;
};
用例
这里的用例是我想将新值重新分配给指针,同时将其保留ResourceManager
为堆栈分配的变量或非指针类成员。
使用我当前的设置,我想像这样使用它:
A a, another_a;
ResourceManager r(&a);
// Use r...
// Destroy old ResourceManager and create the new one in place.
r = ResourceManager(&another_a);
这甚至是一个问题的原因是因为 B 和 C 是不可分配的(例如文件流)
丑陋的替代品
另一种更丑陋(也很危险)的方法是以相反的顺序reset
显式地显式关键字unique_ptr
段(请记住,C 依赖于 B,因此必须首先销毁),有效地模仿默认的销毁行为。
ResourceManager& operator=(ResourceManager&& that) {
// Mimic destructor call (reverse-order destruction)
c_ptr.reset();
b_ptr.reset();
b_ptr = that.b_ptr;
c_ptr = that.c_ptr;
return *this;
}
请注意,错误的实现是简单地将默认赋值运算符用于ResourceManager
. 这将按顺序分配字段,这意味着按顺序销毁unique_ptr
s,而我们需要逆序销毁。
问题
这种使用this
带有放置new
和显式析构函数调用的指针是否安全?
我必须使用返回的new_this
指针而不是原始this
指针(例如,如果this
在调用析构函数后指针在技术上变得无效)?
有没有更好的建议方法来实现这一目标?如果在类中添加更多这样unique_ptr
的字段,我必须确保将副本添加到赋值运算符。例如,是否可以改为调用移动构造函数,如下所示:
ResourceManager& operator=(ResourceManager&& that) {
// Call destructor
~ResourceManager();
// Move-construct a new instance on top
ResourceManager* new_this = new(this) ResourceManager(that);
return *new_this;
}