在"this"指针上使用放置新位置是否安全
Is it safe to use placement new on 'this' pointer
当前实现
我有一个包含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的顺序销毁,而我们需要逆序销毁。
问题
使用放置new
的this
指针和显式析构函数调用是否安全?
我必须使用返回的new_this
指针而不是原始的this
指针吗(例如,如果this
指针在调用析构函数后从技术上变得无效(?
有什么更好的方法可以实现这一点吗?如果向类中添加更多这样的unique_ptr
字段,我必须确保向赋值运算符添加一个副本。例如,是否可以调用move构造函数,如下所示:
ResourceManager& operator=(ResourceManager&& that) {
// Call destructor
~ResourceManager();
// Move-construct a new instance on top
ResourceManager* new_this = new(this) ResourceManager(that);
return *new_this;
}
您的解决方案似乎过于复杂。
我会这样编码:
class ResourceManager {
ResourceManager() {}
ResourceManager(A* a_ptr) :
b_ptr(new B(a)),
c_ptr(new C(b_ptr.get())) {}
ResourceManager& operator=(ResourceManager&& that)
{
// the order of these moves/assignments is important
// The old value of *(this->c_ptr) will be destroyed before
// the old value of *(this->b_ptr) which is good because *c_ptr presumably
// has an unprotected pointer to *b_ptr.
c_ptr = std::move(that.c_ptr);
b_ptr = std::move(that.b_ptr);
// (a better solution might be to use shared_ptr<B> rather than unique_ptr<B>
return *this;
}
unique_ptr<B> b_ptr;
unique_ptr<C> c_ptr;
};
注意:当移动分配返回时,that
将为"空",意味着that.b_ptr
和that.c_ptr
都是nullptr
。这是移动分配的预期结果。
或者,如果"重建"赋值的目标很重要(假设本例中没有显示额外的代码(,我可能会添加一个移动构造函数和一个类似的交换方法:
ResourceManager(ResourceManager&& that)
: b_ptr(std::move(that.b_ptr)),
c_ptr(std::move(that.c_ptr))
{
}
void swap(ResourceManager & that)
{
b_ptr.swap(that.b_ptr);
c_ptr.swap(that.c_ptr);
}
ResourceManager& operator=(ResourceManager&& that)
{
ResourceManager temp(std::move(that));
this->swap(temp);
return *this;
}
相关文章:
- GL_SHADERSTORAGE_BUFFER位置是否与其他着色器位置冲突
- 内存中类位置的成员是否取决于类成员在类定义中的位置?
- 标记为 std::memory_order_seq_cst 的单个原子操作是否会在所有位置触发顺序一致性?
- 是否有任何优雅的方式来遍历元素位置可以更改的列表?
- 是否可以将值分配给移出位置?
- 如果着色器中未使用绑定属性位置,是否会对其进行惩罚
- C++每个变量的存储位置是否正确?
- 在初始化的内存上使用放置新位置是否合法
- 在C++中声明使用的位置是否有良好做法
- C++的最后一个位置是否有计算单元的标准功能
- libvlc 检查媒体位置是否有效
- 更改描述函数行为的位置是否会导致错误?
- 重用内存位置是否安全
- LPCSTR-如何检查第一个位置是否为空格" "
- 检查阵列位置是否为空/空
- 星号的位置是否会影响指针
- 检查数组的X位置是否为char
- 将相同的值写入相同的内存位置是否会导致数据争用?
- 确定一个位置是否是特定列表的成员
- 在"this"指针上使用放置新位置是否安全