如何使用C ++中的共享指针更容易

时间:2010-12-21 08:40:51

标签: c++ visual-studio-2010 c++11 shared-ptr

我正忙于设计一个新的C ++应用程序。在这个应用程序中,我想用指针最小化潜在的错误,因为应用程序应该是普通的C ++(没有.Net或其他奇特的东西),我正在调查共享指针,我正在考虑在任何地方使用共享指针(而不是普通的指针)。

我制定了一些技巧,以便更容易使用共享指针,例如:在类中使用typedef,如下所示:

class X
   {
   public:
      ...
      typedef std::shared_ptr<X> Ptr;
   };

这样你就可以轻松编写X :: Ptr,它比“std :: shared_ptr”更容易编写。

我还注意到共享指针的一些缺点:

  • 无处不在我使用共享指针我需要包含<memory>
  • 如果我只想使用指针
  • ,我就不能再使用前向声明了

是否还有其他技巧可以让共享指针更易于使用?

5 个答案:

答案 0 :(得分:8)

不要!

最小化指针错误的唯一方法是使用正确的指针类型。那是类型,复数。

共享指针不是灵丹妙药。当你有周期性参考时,它们会很快变成内存泄漏(如果计划在任何地方使用它们,那么它们会很快出现)

如果你想要没有错误的C ++应用程序,你必须为它工作。你必须了解你的申请。您必须了解不同对象的所有权语义。共享指针只为您提供共享所有权,这通常是一个不错的最低分母。其他所有东西都可以被共享所有权取代,它会起作用。

但默认情况是对象由一个其他实体拥有。它由函数拥有,并且应该在该函数返回时被销毁,或者它由类或其他任何东西拥有。通常,你根本不需要指针。或许,对象按值存储在std::vector中。或者它只是一个局部变量或类成员。如果 是一个指针,它通常会更好地由scoped_ptr或者可能允许转让所有权(unique_ptrauto_ptr)表示。< / p> 当您无法保证对象的生命周期或所有权时,

shared_ptr就是您可能会遇到的问题。但是当你使用它时,你还需要使用weak_ptr来打破周期。

实际上,更好的方法是尽可能地避免指针。当你需要一个指针时,使用一个具有最特定所有权语义的指针(更喜欢scoped_ptr,根本不允许转让所有权,然后如果你需要它,那么回到允许你移动所有权的一个,例如unique_ptr,并且只作为最后的手段使用shared_ptr,这允许您在任何数字之间自由地共享所有权客户。

没有魔法棒可以让你的C ++代码“正常工作”。实现这一目标的唯一方法是编写良好的可靠C ++代码。你通过了解和使用你可以使用的工具来做到这一点,而不是假装“嘿,shared_ptr就像一个垃圾收集器,不是吗?我可以忽略对象生命周期的所有问题或者如果我使用它,内存泄漏“。

答案 1 :(得分:3)

不要只选择一个智能指针来随处使用。不是每个螺丝都是菲利普斯头。

此外,您可以使用任何智能指针的前向声明与原始指针完全相同:

struct X;

...
std::shared_ptr<X> ptr;  // legal

struct X {};
ptr = std::shared_ptr<X>(new X); // legal

这是我第二次在SO上听到这种误解,而这只是100%错误。

答案 2 :(得分:1)

关于typedef,您应该查看this question,它解决了完全相同的问题。

对于第二部分,我认为你错了,因为std::shared_ptr可以用于N3225的20.9.10.2/2中规定的不完整类型:

  

T的模板参数shared_ptr   可能是一个不完整的类型。

如果您当前的实施不支持,我认为应该将其视为错误。

答案 3 :(得分:1)

代码中很常见的是&#34;约定&#34;然后你跟随它,只要它在整个团队中一致地完成,人们就能理解它。

最好在&#34; forward&#34;中声明共享指针typedef。文件。像这样:

namespace boost { template< typename T > class shared_ptr; }

namespace MyStuff
{
   class Foo;
   class Bar;
   class Baz;

   typedef boost::shared_ptr<Foo> FooPtr;
   typedef boost::shared_ptr<Bar> BarPtr;
   typedef boost::shared_ptr<Baz> BazPtr;

}

您有时会想要使用除shared_ptr之外的其他指针,但您的约定是使用不同的表示形式,XPtr意味着shared_ptr。

当然,您可以使用其他符号。

我认为我们使用FooWeakPtr来表示weak_ptr<Foo> FooConstPtr表示shared_ptr<const Foo>

例如。

应该在您的编码标准文件中。

答案 4 :(得分:0)

我更喜欢这种方法:

   namespace Internal
   {
      template <class T>
      struct DeclareShared
      {
         typedef std::shared_ptr<T> type;
      };

      template <class T>
      struct DeclareUnique
      {
         typedef std::unique_ptr<T> type;
      };
   }

   // Inherit one of these classes to use a generic smart pointer interface.

   // If class is abstract, use this interface.
   template <class T>
   struct SharedAbstract
   {
      typedef typename Internal::DeclareShared<T>::type APtr;
   };

   template <class T>
   struct Shared
   {
      typedef typename Internal::DeclareShared<T>::type Ptr;

      template <class... P>
      static Ptr shared(P&&... args) 
      { 
         return std::make_shared<T>(std::forward<P>(args)...); 
      }
   };

   template <class T>
   struct UniqueAbstract
   {
      typedef typename Internal::DeclareUnique<T>::type AUPtr;
   };

   template <class T>
   struct Unique
   {
      typedef typename Internal::DeclareUnique<T>::type UPtr;

      template <class... P>
      static UPtr shared(P&&... args) 
      { 
         return std::unique_ptr<T>(new T(std::forward<P>(args)...)); 
      }
   };

为scoped ptr等添加了更多接口,无论你想要什么,你都可以做以下事情:

struct Foo : public Shared<Foo>, public Unique<Foo>
{};

Foo::Ptr foo = Foo::shared();
Foo::UPtr unique = Foo::unique();

我不确定VS10如何应对可变参数模板,但这至少可以在GCC4.5 +上正常工作。