我正在尝试使用 unique_ptr 并编写一些简单的代码来检查它如何与移动语义一起使用。
#include <iostream>
#include <vector>
using namespace std;
class X
{
public:
X(){}
~X() { cout << "Destructor X" << endl; }
void Print() { cout << "X" << endl; }
};
int main()
{
unique_ptr<X> ptr(new X());
ptr->Print();
vector<unique_ptr<X>> v;
v.push_back(move(ptr));
ptr->Print();
v.front()->Print();
return 0;
}
输出如下:
X
X
X
Destructor X
我的期望是在push_back之后原始的unique_ptr ptr 会失效。但Print()方法被调用就好了。这种行为会有什么解释?
答案 0 :(得分:12)
我的期望是在push_back之后原始的unique_ptr ptr会失效。
它设置为空指针。您可以通过将其与nullptr
进行比较来检查。
但
Print()
方法被称为正常。对这种行为有什么解释?
您正在调用空指针上的成员函数,这是未定义的行为。该成员函数实际上并不访问类中的任何数据,因此它不会崩溃,但它仍然是未定义的行为。
您获得此程序的类似行为,它与unique_ptr
无关:
int main()
{
X x;
X* ptr = &x;
ptr->Print();
ptr = nullptr;
ptr->Print();
}
它似乎工作正常,因为X::Print()
实际上没有从this
指针读取任何内容。如果更改X::Print()
的定义以访问类中的某些成员数据,则可能会因解除引用空指针而崩溃。
有关详细信息,请参阅When does invoking a member function on a null instance result in undefined behavior?。
答案 1 :(得分:5)
你所拥有的是明确未定义的行为。如果我用以下
替换main
的内容
int main()
{
unique_ptr<X> ptr;
ptr->Print();
cout << (static_cast<bool>(ptr) ? "active\n" : "inactive\n");
}
gcc和clang仍然是print
X
inactive
你正在调用nullptr
上的成员函数,我猜它恰好起作用,因为成员函数实际上并没有使用this
指针。将您的班级定义更改为:
class X
{
int y = 0;
public:
X(){}
~X() { cout << "Destructor X" << endl; }
void Print() { cout << "y = " << y << endl; }
};
现在您的原始代码会导致细分错误,因为它会尝试取消引用nullptr
。
至于你期望unique_ptr
在你离开之后无效,你绝对是正确的。这是由标准保证的。
§20.8.1/ 4 [unique.ptr]
此外,
u
可以根据请求将所有权转让给另一个唯一指针u2
。完成转移后,以下后置条件成立:
-u2.p
等于转帐前u.p
,
-u.p
等于nullptr
和
...
高于u
&amp; u2
是unique_ptr
个对象,p
是指向托管对象的指针。