如何最好地传递shared_ptr?
目前我是这样传递shared_ptr函数参数的:
void function1( shared_ptr<TYPE>& value );
如何最好地传递shared_ptr?
目前我是这样传递shared_ptr函数参数的:
void function1( shared_ptr<TYPE>& value );
SF = std::shared_ptr<Foo>
。为了考虑引用,而不是传递函数参数,我们看一下类型RSF = std::reference_wrapper<T>
。也就是说,如果我们有一个共享指针SF p(std::make_shared<Foo>())
,那么我们可以通过RSF w = std::ref(p)
创建一个具有值语义的引用包装器。至此,设置完成。现在,每个人都知道指针容器是个雷区。因此,std::vector<Foo*>
将是一个维护困难的噩梦,并且由于未正确管理生命周期而产生任意数量的错误。更糟糕的是,从概念上讲,从容器存储指针的对象中清楚地知道谁拥有这些对象是不可能的。这些指针甚至可以是动态对象、自动对象和垃圾的混合物,没有人能够确定。因此,标准解决方案是使用 std::vector<SF>
。这是正确使用共享指针的方法。另一方面,绝不能使用的是 std::vector<RSF>
,这是一个无法管理的怪兽,实际上非常类似于原始裸指针的向量!例如,你不清楚你所持有的引用指向的对象是否还活着。获取共享指针的引用已经打败了它的整个目的。SF p
。现在我们有一个函数 int foo(SF)
,我们希望同时运行它。通常的 std::thread(foo, p)
就可以正常工作,因为线程构造函数将其参数的副本。然而,如果我们说 std::thread(foo, std::ref(p))
,我们会遇到各种麻烦:调用范围内的共享指针可能会过期并销毁对象,你将留下一个悬空引用和无效指针!这取决于您的需求。被调用者是否需要共享对象的所有权?那么它需要自己的 shared_ptr
的副本。因此,通过值传递。
如果函数只需要访问由调用者拥有的对象,则继续传递(const)引用,以避免复制 shared_ptr
的开销。
C++ 中最佳实践是始终为您的对象定义清晰的所有权语义。没有通用的“总是这样做”来替代实际的思考。
如果您总是按值传递共享指针,那么会变得很昂贵(因为它们比原始指针更昂贵)。如果您从不这样做,那么使用共享指针就没有意义。
当新函数或对象需要共享指针所指向的对象的所有权时,请复制共享指针。
void store( shared_ptr<T> const& sharedRef ) { this->mySharedRef=shredRef;}
。如果传递的是按值传递,则计数器会增加两次。当然,你可以使用void store( shared_ptr<T> sharedRef ) { shredRef.swap(this->mySharedRef);}
来实现同样的功能。 - Arpegius如果你使用引用传递,请通过const引用传递。这可以清楚地表明你是出于性能原因而进行引用传递。另外,尽可能使用make_shared,因为它可以节省一次间接引用,从而提高性能。
make_shared
总是一个好选择,但请注意它仅在创建第一个共享指针时才起作用。 - Kerrek SBstd::make_shared
可能会使可执行映像文件的二进制大小有点膨胀,无论分配是否实际上有助于运行时性能。这对于桌面/服务器平台不应该是问题,但对于资源极其有限的嵌入式环境可能会成为问题。 - FrankHBtypeid
。然而,我不能直接使用它,因为该类型未公开。例如,当启用RTTI时,libstdc++使用typeid(_Sp_make_shared_tag)
获取由allocate_shared
/make_shared
分配的shared_ptr
的删除器。如果我仍然需要其他地方使用RTTI,则无法禁用它,而不修改头文件源代码。实际上,结果的type_info
只是一个占位符,真正需要运行时类型信息。因此,像boost::typeindex::type_id
这样的东西应该能够改善情况。 - FrankHB