8

我有foo一个包含我想复制构造的 std::auto_ptr 成员的类,但这似乎是不允许的。作业也有类似的情况。请参见以下示例:

struct foo
{
private:
    int _a;
    std::string _b;
    std::auto_ptr< bar > _c;

public:
    foo(const foo& rhs)
        :   _a(rhs._a)
        ,   _b(rhs._b)

        ,   _c(rhs._c)
                // error: Cannot mutate rhs._c to give up ownership - D'Oh!
    {
    }

    foo& operator=(const foo& rhs)
    {
         _a = rhs._a;
         _b = rhs._b;

         _c = rhs._c;
             // error: Same problem again.
    }
};

我可以声明_c为,mutable但我不确定这是正确的。有没有人有更好的解决方案?

编辑

好的,我没有得到我期望的那种答案,所以我会更具体地说明这个问题。

  • 类型的对象foo在堆栈上创建并按值传递给容器类(不是 stl),然后超出范围。我无法控制容器代码。(它实际上是一个活动队列实现,有错误。)
  • 该类bar是一个相当重量级的解析器。它的性能非常差newdelete因此即使它是可复制的,也太昂贵了。
  • 我们可以保证,当一个bar对象被创建时,它一次只需要在一个地方拥有。在这种情况下,它在线程之间传递并在事务完成时被删除。这就是为什么我希望使用std::autp_ptr.
  • 我非常愿意考虑提升智能指针,但如果有替代方案,我希望能保证这种唯一性。
4

9 回答 9

16

您可能想尝试以下代码:

    foo(const foo& rhs)
        :   _a(rhs._a)
        ,   _b(rhs._b)
        ,   _c(_rhs._c.get() ? new bar(*_rhs._c.get()) : 0)
    {
    }

(赋值运算符类似。)

但是,这只有在barCopyConstructible 并且确实可以满足您的要求时才有效。问题是两个foo对象(_rhs和构造的一个)在_c.

如果您希望他们共享指针,那么您不能使用auto_ptr它,因为它不支持共享所有权。例如在这种情况下考虑使用shared_ptr来自Boost.SmartPtr(将包含在新的 C++ 标准中)。或任何其他共享指针实现,因为这是一个常见的概念,有很多实现可用。

于 2009-07-17T11:25:49.953 回答
8

正如您所发现的那样,您不能复制std::auto_ptr这样的内容。拷贝后指向的对象是谁拥有?相反,您应该使用引用计数的智能指针。Boost 库有一个您可以使用的shared_ptr 。

于 2009-07-17T11:21:47.263 回答
3

首先,我会避免使用 auto_ptr

在某些情况下,所有权转移是好的,但我发现它们很少见,而且“成熟的”智能指针库现在很容易获得。(IIRC auto_ptr 是在标准库中包含至少一个示例的一种折衷方案,没有良好实现所需的延迟)。

参见,例如这里
或这里

确定语义
foo 的副本是否应该包含对同一个 bar 实例的引用?在这种情况下,请使用boost::shared_ptror ( boost::intrusive_ptr) 或类似的库。

还是应该创建一个深层副本?(有时可能需要这样做,例如当具有延迟创建状态时)。我不知道该概念的任何标准实现,但构建类似于现有智能指针的东西并不复杂。

   // roughly, incomplete, probably broken:
   template <typename T>
   class deep_copy_ptr
   {
      T * p;
     public:
      deep_copy_ptr()  : p(0) {}
      deep_copy_ptr(T * p_)  : p(p_) {}
      deep_copy_ptr(deep_copy_ptr<T> const & rhs)  
      {
        p = rhs.p ? new T(*rhs.p) : 0;
      }
      deep_copy_ptr<T> & operator=(deep_copy_ptr<T> const & rhs)
      {
         if (p != rhs.p)
         {
           deep_copy_ptr<T> copy(rhs);
           swap(copy);
         }
      }
      // ...
   }
于 2009-07-17T11:44:55.687 回答
1

std::auto_ptr是在 C++ 中管理动态对象的好工具,但为了有效地使用它,了解 auto_ptr 的工作原理很重要。本文解释了为什么、何时以及何地应该使用这个智能指针。

在您的情况下,首先您应该决定要对 auto_ptr 中的对象做什么。它应该被克隆还是共享?

如果应该克隆它,请确保它具有复制构造函数,然后创建一个新的 auto_ptr ,其中包含对象的副本,请参阅Adam Badura的答案。

如果应该共享,您应该按照Martin Liversage的建议使用boost::shared_ptr 。

于 2009-07-17T11:48:20.390 回答
1

如果我有一个包含 auto_ptr 的类,并且想要深度复制语义,我通常只对具有虚拟复制运算符的类执行此操作,即 clone()。

然后,在复制构造函数中,我将 auto_ptr 初始化为另一个的 clone();例如

class Foo
{
   public:
      Foo(const Foo& rhs) : m_ptr(rhs.m_ptr->clone());
   private:
      std::auto_ptr<T> m_ptr;
};

clone() 通常实现如下:

class T
{
   std::auto_ptr<T> clone() const
   {
      return std::auto_ptr<T>(new T(*this));
   }
};

我们强加了 T 是可克隆的条件,但这个条件本质上是通过拥有一个带有 auto_ptr 成员的可复制类来强加的。

于 2009-07-17T17:59:17.923 回答
0

的整个想法auto_ptr是被引用对象只有一个所有者。这意味着您不能在不删除原始所有权的情况下复制指针。

由于您无法复制它,因此您也无法复制包含auto_ptr.

std::swap您可能会尝试通过使用而不是复制来使用移动语义。

于 2009-07-17T11:36:21.553 回答
0

我的第一选择是在这种情况下完全避免使用 auto_ptr。但是如果我靠墙支持,我可能会尝试mutable在 _c 的声明中使用关键字 - 这将允许它甚至可以从 const 引用进行修改。

于 2009-07-17T15:17:39.827 回答
0

鉴于编辑,您似乎想要转让所有权语义。

在这种情况下,您将希望您的复制构造函数和赋值运算符接受对其参数的非常量引用,并在那里执行初始化/赋值。

于 2009-07-17T18:04:36.557 回答
-1

您不能在涉及auto_ptr<>. 删除常量。换句话说,使用像这样的声明

foo(foo & rhs);
foo & operator=(foo & rhs);

这些形式在标准中明确提到,主要在第 12.8 节中。它们应该可用于任何符合标准的实现。事实上,12.8 的第 5 和 10 段说,如果任何成员需要,隐式定义的复制构造函数和赋值运算符(分别)将采用非常量引用。

于 2009-07-17T15:30:36.947 回答