移动后,唯一指针仍然保持对象

时间:2016-06-25 10:23:44

标签: c++ pointers

我正在阅读有关智能指针在 C ++ 中如何工作的一些教程,但我仍然坚持我尝试的第一个:唯一指针。我正在遵循wikipediacppreferencecplusplus的指南。我已经看过this answer了。如果我理解正确的话,唯一的指针应该是对某个存储单元/块具有所有权的唯一指针。这意味着只有唯一指针(应该)指向该单元格而没有其他指针。从维基百科,他们使用以下代码作为示例:

LayoutInflater

直到第二行,当我测试它时,这对我来说很好。但是,在移动第一个唯一指针指向第二个唯一指针之后,我发现两个指针都可以访问同一个对象。我认为整个想法是让第一个指针变得毫无用处可以这么说?我期望一个空指针或一些未确定的结果。我跑的代码:

MyAdapter adapter = new MyAdapter(MainActivity.this, list);

此处std::unique_ptr<int> p1(new int(5)); std::unique_ptr<int> p2 = p1; //Compile error. std::unique_ptr<int> p3 = std::move(p1); //Transfers ownership. p3 now owns the memory and p1 is rendered invalid. p3.reset(); //Deletes the memory. p1.reset(); //Does nothing. 已移至class Figure { public: Figure() {} void three() { cout << "three" << endl; } }; class SubFig : public Figure { public: void printA() { cout << "printed a" << endl; } }; int main() { unique_ptr<SubFig> testing (new SubFig()); testing->three(); unique_ptr<SubFig> testing2 = move(testing); cout << "ok" << endl; int t; cin >> t; // used to halt execution so I can verify everything works up til here testing->three(); // why is this not throwing a runtime error? } ,因此我很惊讶地发现我仍然可以在testing上调用方法testing2

此外,调用 reset()似乎并没有像它所说的那样删除内存。当我修改main方法成为:

three()

我希望testing不能用于int main() { unique_ptr<SubFig> testing (new SubFig()); testing->three(); unique_ptr<SubFig> testing2 = move(testing); cout << "ok" << endl; int t; cin >> t; testing.reset(); // normally this should have no effect since the pointer should be invalid, but I added it anyway testing2.reset(); testing2->three(); } ,因为维基百科的例子提到应该通过重置删除内存。我还在打印打印,好像一切都很好。这对我来说似乎很奇怪。

所以任何人都可以向我解释原因:

  • 从一个唯一指针移动到另一个唯一指针不会使第一个无效吗?
  • 重置实际上删除内存?调用three()时实际发生了什么?

3 个答案:

答案 0 :(得分:6)

基本上,您通过空指针调用成员函数:

int main()
{
    SubFig* testing = nullptr;
    testing->three();
}

...这是未定义的行为。

从20.8.1类模板unique_ptr(N4296)

  

4此外,您可以根据要求将所有权转让给另一个人   独特的指针u2。完成此类转让后,如下   后置条件持有:

     
      
  • u2.p等于转移前的u.p,
  •   
  • u.p等于nullptr
  •   
  • 如果预转移u.d维持状态,则此状态已转移到u2.d。
  •   

(强调我的)

答案 1 :(得分:4)

std::move()原始指针testing设置为nullptr后。

std::unique_ptr检查空访问权以抛出运行时错误的可能原因是每次使用std::unique_ptr时速度都会变慢。通过不进行运行时检查,编译器可以完全优化std::unique_ptr调用,使其与使用原始指针一样高效。

在调用nullptr时您没有遇到崩溃的原因可能是因为您调用的函数无法访问(不存在的)对象的内存。但它是未定义的行为所以任何事情都可能发生。

答案 2 :(得分:2)

在调用std::unique_ptr<int> p3 = std::move(p1);时,原始指针p1处于未定义状态,因此使用它将导致未定义的行为。简单地说,永远不要这样做。