C++ 我应该通过引用传递共享的\u ptr吗?
通过共享ptr的最佳实践是什么 目前我传递共享的函数参数如下:C++ 我应该通过引用传递共享的\u ptr吗?,c++,shared-ptr,C++,Shared Ptr,通过共享ptr的最佳实践是什么 目前我传递共享的函数参数如下: void function1( shared_ptr<TYPE>& value ); void函数1(共享值); 在受控环境中,您可以通过常量引用传递共享指针。确保没有人同时删除该对象,尽管如果您对引用对象的人很小心,这应该不会太困难 通常,应该将共享指针作为直接副本传递。这赋予了它预期的语义:每个包含共享指针副本的作用域通过其在所有权中的“共享”保持对象的活动 不总是按值传递的唯一原因是,由于原子引用计数的更
void function1( shared_ptr<TYPE>& value );
void函数1(共享值);
在受控环境中,您可以通过常量引用传递共享指针。确保没有人同时删除该对象,尽管如果您对引用对象的人很小心,这应该不会太困难
通常,应该将共享指针作为直接副本传递。这赋予了它预期的语义:每个包含共享指针副本的作用域通过其在所有权中的“共享”保持对象的活动
不总是按值传递的唯一原因是,由于原子引用计数的更新,复制共享指针的代价是一定的;然而,这可能不是一个主要问题
可选题外话:
既然已经回答了主要问题,那么考虑使用强指针> <强>绝对/强>的几种方法可能是有益的。这里有一个小小的思想实验。让我们定义一个共享指针类型
SF=std::shared\u ptr
。为了考虑引用,而不是传递函数参数,让我们看看类型<代码> RSF= STD::RealthyTyWraser-<代码>。也就是说,如果我们有一个共享指针sfp(std::make_shared())
,然后我们可以通过rsfw=std::ref(p)生成具有值语义的引用包装器代码>。设置到此为止
现在,每个人都知道指针的容器是雷区。因此,std::vector的维护将是一场噩梦,任何数量的bug都是由不当的生命周期管理引起的。从概念上讲,更糟糕的是,永远不清楚谁拥有容器存储的指针的对象。指针甚至可以是指向动态对象、自动对象和垃圾的指针的混合体。谁也说不出来。因此,标准解决方案是使用std::vector
。这是使用共享指针的正确方法。另一方面,您绝对不能使用的是std::vector
——这是一个无法管理的怪物,实际上与裸指针的原始向量非常相似!例如,不清楚您持有引用的对象是否仍然存在。引用共享指针已经破坏了它的全部用途
对于第二个示例,假设我们有一个与前面一样的共享指针sfp
。现在我们有了一个要并发运行的函数intfoo(SF)
。通常的std::thread(foo,p)
工作得很好,因为线程构造函数复制了它的参数。然而,如果我们说std::thread(foo,std::ref(p))
,我们会遇到各种各样的麻烦:调用范围中的共享指针可能会过期并销毁对象,而您将留下一个悬空引用和一个无效指针
我希望这两个公认的相当做作的例子能为您真正希望共享指针通过副本传递提供一些帮助。在一个设计良好的程序中,应该始终明确谁负责哪些资源,并且在正确使用时,共享指针是一个很好的作业工具。如果按引用传递,则按常量引用传递。这清楚地表明,由于性能原因,您通过ref。另外,尽可能使用make_shared,因为它可以节省一个间接寻址,从而提高性能。这取决于您想要什么。被调用方是否应该共享对象的所有权?然后它需要自己的共享\u ptr
副本。所以按值传递它
如果函数只需要访问调用者拥有的对象,请继续并传递(const)引用,以避免复制共享\u ptr
的开销
< > C++中的最佳实践总是为对象定义清楚的所有权语义。没有普遍的“总是这样做”来代替实际的想法
如果总是按值传递共享指针,那么代价会很高(因为复制它们比原始指针要昂贵得多)。如果你从未这样做过,那么首先使用共享指针是没有意义的
当新函数或对象需要共享指针对象的所有权时,复制共享指针。使共享始终是一件好事,但请注意,它仅在创建第一个共享指针时起作用。@Kerrek SB:不总是正确的。对于一些典型的实现,std::make_shared
会因为RTTI的东西而使可执行映像的二进制大小有点膨胀,不管这种分配是否会真正有利于运行时性能。对于桌面/服务器平台来说,这不应该是一个问题,但是对于资源极其有限的嵌入式环境来说,这可能是一个问题。@FrankHB:对于其他实现来说,“RTTI东西”怎么可能不存在呢?对于您使用的每一个新类型,您总是会增加二进制大小,因此您最多可以尝试避免对同一类型使用两个不同的实现。@KerrekSB:二进制大小会膨胀,因为库使用typeid
进行内部实现。但是,我不能直接使用它,因为类型没有公开。例如,启用RTTI时,libstdc++使用typeid(\u Sp\u make\u shared\u标记)
获取shared\u ptr
分配给allocate\u shared
的deleter。如果我在其他地方仍然需要RTTI,我没有选择在不修改标题中的源代码的情况下禁用它。实际上,生成的type\u info
是一个占位符,实际上不需要运行时类型信息。所以类似于boost::typeindex::type_id
的东西应该会让事情变得更好。你能详细解释一下“并发删除对象”的意思吗?你是在暗示,在你通过引用传递任何东西时,除了“通常”出现的危险之外,还有什么危险吗?@wolfgang:我刚刚发布了一个l