gpt4 book ai didi

c++ - 在 'this' 指针上使用 placement new 是否安全

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:37:50 25 4
gpt4 key购买 nike

当前实现

我有一个包含 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 是不可分配的(例如文件流)

丑陋的选择

另一种更丑陋(和危险)的方法是显式重置 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 的按顺序销毁,而我们需要逆序销毁。

问题

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

最佳答案

您的解决方案似乎过于复杂。

我会这样编码:

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_ptrthat.c_ptr 都是 空指针。这是移动分配的预期结果。

或者如果“重构”赋值的目标很重要(假设有额外的代码没有在这个例子中显示)我可能会像这样添加一个移动构造函数和一个交换方法:

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

关于c++ - 在 'this' 指针上使用 placement new 是否安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23370330/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com