C++ 在移动唯一的ptr时,是否可以移动它';它在自己的析构函数中?
昨天我遇到一个类,该类在其析构函数中调用一个方法,该方法最终返回一个唯一的\u ptr到C++ 在移动唯一的ptr时,是否可以移动它';它在自己的析构函数中?,c++,c++11,C++,C++11,昨天我遇到一个类,该类在其析构函数中调用一个方法,该方法最终返回一个唯一的\u ptr到this。这显然是一个问题,因为这会导致双重删除,所以我在该方法调用中添加了.release(),一切又恢复正常。这是一个奇怪的情况,虽然,我想有一些结束,这是一个好的事情做 举个例子,我将这种情况归结为其本质: #include <memory> class B; class A { public: A(std::unique_ptr<B> b); std::uniqu
this
。这显然是一个问题,因为这会导致双重删除,所以我在该方法调用中添加了.release()
,一切又恢复正常。这是一个奇怪的情况,虽然,我想有一些结束,这是一个好的事情做
举个例子,我将这种情况归结为其本质:
#include <memory>
class B;
class A {
public:
A(std::unique_ptr<B> b);
std::unique_ptr<B> removeB();
private:
std::unique_ptr<B> b_;
};
class B {
public:
B();
~B();
void setA(A *a);
private:
A *a_;
};
A::A(std::unique_ptr<B> b)
: b_(std::move(b))
{
b_->setA(this);
}
B::B()
: a_(nullptr)
{
}
B::~B()
{
if (a_)
a_->removeB().release();
}
void B::setA(A *a)
{
a_ = a;
}
std::unique_ptr<B> A::removeB()
{
return std::move(b_);
}
int main(int argc, char *argv[])
{
A a(std::make_unique<B>());
}
它工作正常,我没有任何静态分析仪或valgrind对此抱怨,但我想确认一下,这是一件可以做的事情。这里发生了一些非常复杂的事情。首先,您有
A类
,它有一个与AB
唯一的ptr
。这表明了所有权(或父/子)关系:A
拥有AB
。B
又有一个指向a
的简单指针,该指针不是在构造函数中设置的,而是通过setA
调用来设置的,这一事实似乎证实了这一点:a
获取一个子B
,然后用一个简单的指针对其调用setA
,告诉B
那么B
什么时候被销毁?答:在A
的销毁过程中,通过unique\ptr
的析构函数。当removeB
调用发生这种情况时,为什么B
会尝试将自己从A
上拉下来?这看起来像是混乱的代码,根本不需要存在。正确的方法可能是在B
的析构函数中什么都不做,然后所有的东西都会被正确地销毁
因此,我的建议是为B
使用一个空的析构函数
回答您的具体问题:这个
removeB()。在A
的销毁过程中调用B
析构函数,因此在A
的唯一\u ptr
成员的销毁过程中发生。因此,您的removeB
调用将部分销毁的对象传递给unique\u ptr
的移动构造函数。如果这是未定义的行为,我不会感到惊讶。是否“这是一件可以做的事情”取决于应用程序的其余部分如何使用这些类。所以,恐怕你是唯一一个能确定“这是一件可以做的事情”的人。我的意思是,这更像是一个基本的问题:这能保证在任何编译器、任何平台、任何stdlib实现(不包括bug)上工作吗?这是一个非常棘手的问题。我认为这实际上取决于编译器的实现。不是100%确定,但是如果编译器支持c++11,我看不出有什么问题。因为这些类是紧密耦合的,你不能简单地合并它们吗?为什么你的析构函数需要调用一个返回唯一的\u ptr
,引用这个?我询问的原因是,创建(或返回)一个唯一\u ptr
与对象的初始化(*此不能在其析构函数中初始化)或防止其销毁(如果调用析构函数,则对象的销毁已不可撤销地开始)相关。强制unique_ptr
释放(因此不销毁对象)将起作用,但在析构函数中执行此操作的需要表明设计严重受损。在我们的特定情况下,如果在析构函数中调用removeB
,则应始终返回nullptr
,但是有一个bug导致它返回一个实际的有效指针。
class B;
class A {
public:
A(B* b);
~A();
B *removeB();
private:
B *b_;
};
class B {
public:
B();
~B();
void setA(A *a);
private:
A *a_;
};
A::A(B *b)
: b_(b)
{
b_->setA(this);
}
A::~A()
{
delete b_;
}
B::B()
: a_(nullptr)
{
}
B::~B()
{
if (a_)
a_->removeB();
}
void B::setA(A *a)
{
a_ = a;
}
B *A::removeB()
{
B *result = b_;
b_ = nullptr;
return result;
}
int main(int argc, char *argv[])
{
A a(new B());
}