C++ 使用std::move和std::shared\u ptr的好处和风险是什么
我正在学习C++11的特性,作为其中的一部分,我将率先进入C++ 使用std::move和std::shared\u ptr的好处和风险是什么,c++,c++11,shared-ptr,move-semantics,unique-ptr,C++,C++11,Shared Ptr,Move Semantics,Unique Ptr,我正在学习C++11的特性,作为其中的一部分,我将率先进入独特的\u ptr和共享的\u ptr世界 当我开始时,我编写了一些专门使用unique\u ptr的代码,因此当我传递变量时,我需要使用std::move来完成这项工作(或者我是这样理解的) 经过一番努力,我意识到我真正需要的是共享\u ptr,而不是我正在做的事情。稍后快速查找/替换,我的指针切换到共享,但我只是懒洋洋地保留了move()调用 令我惊讶的是,它不仅编译了,而且在我的程序中表现得非常好,我得到了我所期望的每一点功能。。。
独特的\u ptr
和共享的\u ptr
世界
当我开始时,我编写了一些专门使用unique\u ptr
的代码,因此当我传递变量时,我需要使用std::move
来完成这项工作(或者我是这样理解的)
经过一番努力,我意识到我真正需要的是共享\u ptr
,而不是我正在做的事情。稍后快速查找/替换,我的指针切换到共享,但我只是懒洋洋地保留了move()
调用
令我惊讶的是,它不仅编译了,而且在我的程序中表现得非常好,我得到了我所期望的每一点功能。。。特别是,我能够将ashared_ptr
从ObjectA“移动”到ObjectB,两个对象都可以访问它并对其进行操作。太棒了
这给我提出了一个问题。。。既然我在shared\u ptr
,调用move()
是否真的在做什么?如果是的话,是什么,以及它的后果是什么
代码示例
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));
shared_ptr lblLevel(新标签());
//levelTest在我的类的接口中声明为shared_ptr,目前尚未定义
levelTest=lblLevel;
//用一些修改过的代码配置我的标签
//将标签传递给一个容器,该容器将共享的ptr存储在std::list中
//该std::list在渲染阶段迭代,将文本渲染到屏幕
这->guiView.AddSubview(move(lblLevel));
在这一点上,我可以对levelTest进行重要的更改,比如更改文本,这些更改会反映在屏幕上
在我看来,似乎列表中的
levelTest
和shared\u ptr都是同一个指针,而且move()
确实做得不多。这是我业余的口译。寻找洞察力。在Windows上使用MinGW 根据20.7.2.2.1,从可转换类型的共享指针移动构造或移动赋值时,源指针变为空:
22-后置条件:*此
应包含r
的旧值<代码>r应为空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);
std::shared_ptr p=std::make_shared(5);
std::shared_ptr q=std::move(p);
断言(p.get()==nullptr);
如果复制共享\u ptr,指针目标的引用计数将增加(以线程安全的方式)
相反,当您将共享_ptr从a移动到B时,B包含移动前a状态的副本,a为空。没有线程安全的引用计数递增/递减,但在A和B的内部位之间有一些非常简单且廉价的指针交换
您可以将移动视为从移动源到移动目的地“窃取资源”的一种有效方式。ecatmur的回答解释了从一般意义上看事情为何会发生这样的行为 特别是对于您的情况,
levelTest
是lblTest
的一个副本,它创建了对共享资源的额外拥有引用。您从lblTest
移动,因此levelTest
完全不受影响,其对资源的所有权保持不变
如果您查看lblTest
我相信您会看到它被设置为空值。由于您在移出shared_ptr
之前复制了它,指针的现有活动实例(levelTest
和guiView
中的值)应该引用相同的底层指针(它们的get
方法返回相同的值),并且应该至少有两个引用(他们的use\u count
方法应返回2
,如果您制作了其他副本,则返回更多)
shared\u ptr
的全部意义在于,当所有shared\u ptr
实例都被破坏时,在允许自动清理资源的同时启用您看到的东西。嗨,ecatmur,我用一个简短的代码示例进行了编辑。我很有信心当前代码中的nullptr也不是空的。我希望这能提供清晰的信息。我想完全理解这一点,所以我不只是到处乱扔垃圾。@JasconiusAddSubview
的签名是什么?@Jasconius好的,所以lblLevel
被移走了,但这不会影响levelTest
。这是意料之中的。不,实际上没有区别-使用move
您正在保存一个原子公司请记住,这是一个很小的成本。@ecatmur“通过使用移动,您可以节省一个原子增量”和一个随后的减量……不一定是一个“小成本”对于所有架构-即使假设最小的争用/旋转-给定它可以在其他线程/核心下一步修改计数器之前强制缓存同步。与互斥量相比,原子增量便宜,但与许多其他东西相比-不是。请注意,ifAddSubView
通过左值引用获取其参数(尤其是常量左值引用),这将撤消move()
(毕竟,这只是一个强制转换)的效果,并且可能会生成一个(可能是临时的)副本。在这种情况下,您可能仍然会发现lblLevel
是非空的。