使用std :: move和std :: shared_ptr有什么好处和风险(如果有的话)

时间:2014-04-09 22:53:03

标签: c++ c++11 shared-ptr move-semantics unique-ptr

我正在学习C ++ 11的功能,作为其中的一部分,我首先潜入unique_ptrshared_ptr的世界。

当我开始时,我写了一些专门使用unique_ptr的代码,因此当我传递我的变量时,我需要用std::move完成它(或者我理解了)

经过一番努力,我意识到我真的需要shared_ptr而不是我正在做的事情。稍后快速查找/替换,我的指针被切换为共享,但我懒得离开move()来电。

令我惊讶的是,这不仅仅是编译,而且在我的程序中表现得非常好,我得到了我期待的每一项功能......特别是,我能够"移动"从ObjectA到ObjectB的shared_ptr,两个对象都可以访问它并可以对其进行操作。奇妙。

这为我提出了一个问题,但是...... move()现在shared_ptr实际上正在做任何事情吗shared_ptr<Label> lblLevel(new Label()); //levelTest is shared_ptr<Label> declared in the interface of my class, undefined to this point levelTest = lblLevel; //Configure my label with some redacted code //Pass the label off to a container which stores the shared_ptr in an std::list //That std::list is iterated through in the render phase, rendering text to screen this->guiView.AddSubview(move(lblLevel)); ?如果是这样,它会产生什么影响呢?

代码示例

levelTest

此时,我可以对levelTest进行重要更改,例如更改文本,这些更改会反映在屏幕上。

这对我来说似乎move()和列表中的shared_ptr都是相同的指针,而{{1}}确实没有做太多。这是我的业余解释。寻找洞察力。在Windows上使用MinGW。

3 个答案:

答案 0 :(得分:4)

ecatmur的回答解释了为什么你会在一般意义上看到事物的行为。

特别针对您的情况,levelTestlblTest副本,它创建了对共享资源的额外拥有引用。您从lblTest移出,因此levelTest完全不受影响,且资源的所有权保持不变。

如果您查看lblTest我确定您已将其设置为空值。因为您在移动它之前制作了shared_ptr的副本,所以指针的现有实例(levelTestguiView中的值)都应引用相同的基础指针(他们的get方法返回相同的值)并且应该至少有两个引用(他们的use_count方法应该返回2,如果你做了额外的副本,则更多。)

shared_ptr的重点在于,在所有shared_ptr个实例都被销毁的情况下仍然允许自动清理资源时,启用像您一样的内容。

答案 1 :(得分:3)

当您从可转换类型的共享指针移动构造或移动分配时,源指针变为空,符合20.7.2.2.1:

  

22 - 后置条件*this应包含旧值rr为空r.get() == 0

因此,如果您在移动构造或移动分配后观察到源指针仍然有效,那么您的编译器不正确或者您使用的std::move不正确。

例如:

std::shared_ptr<int> p = std::make_shared<int>(5);
std::shared_ptr<int> q = std::move(p);
assert(p.get() == nullptr);

答案 2 :(得分:2)

如果你复制一个shared_ptr,指针目标的引用计数会递增(以线程安全的方式)。

相反,当您一个shared_ptr从A移动到B时,B包含移动前A的状态副本,而A为空。没有线程安全的引用计数递增/递减,但A和B的内部位之间有一些非常简单和便宜的指针交换。

您可以将移动视为&#34;从移动源移动到移动目的地的资源&#34; 的有效方式。