如何在必须复制构造的类中使用 std::auto_ptr ?

发布于 2024-07-27 17:35:44 字数 1096 浏览 11 评论 0原文

我有一个包含 std::auto_ptr 成员的类 foo,我想复制该成员,但这似乎是不允许的。 任务中也有类似的事情。 请参阅以下示例:

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 对象时,一次只需要在 1 个位置拥有它。 在这种情况下,它在线程之间传递,并在事务完成时被删除。 这就是为什么我希望使用 std::autp_ptr 。
  • 我非常愿意考虑增强智能指针,但我希望如果有替代方案的话能够保证这种唯一性。

I have class foo that contains a std::auto_ptr member that I would like to copy construct but this does not appear to be allowed. There's a similar thing for the assignment. See the following example:

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.
    }
};

I could just declare _c as mutable but I'm not sure this is correct. Does anyone have a better solution?

EDIT

OK, I'm not getting the kind of answer that I was expecting so I'll be a little more specific about the problem.

  • An object of type foo is created on the stack and passed by value into a container class (not stl) and then goes out of scope. I don't have any control over the container code. (It's actually an active queue implementation, with bugs.)
  • The bar class is a fairly heavyweight parser. It has very poor performance on new and delete so even if it was copy constructable, it would be way too expensive.
  • We can guarantee that when a bar object is created, it will only ever need to be owned in 1 place at a time. In this case it is being passed between threads and deleted when the transaction is completed. This is why I was hoping to use a std::autp_ptr.
  • I am very willing to consider boost smart pointers but I was hoping to guarantee this uniqueness if there is an alternative.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

晨曦÷微暖 2024-08-03 17:35:44

您可能想尝试以下代码:(

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

赋值运算符类似。)

但是,只有当 bar 是可复制构造的并且确实满足您的要求时,这才有效。 问题是,两个 foo 对象(_rhs 和构造对象)在 _c 中将具有不同的指针。

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

You might want to try following code:

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

(Assignment operator is similar.)

However this will only work if bar is CopyConstructible and if this indeed does what you want. The thing is that both foo objects (_rhs and constructed one) will have different pointers in _c.

If you want them to share the pointer then you must not use auto_ptr as it does not support shared ownership. Consider in such case use of shared_ptr from Boost.SmartPtr for example (which will be included in new C++ standard). Or any other shared pointer implementation as this is such a common concept that lots of implementations are available.

深爱不及久伴 2024-08-03 17:35:44

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

As you have discovered you can't copy a std::auto_ptr like that. After the copy who owns the object pointed to? Instead you should use a reference counted smart pointer. The Boost library has a shared_ptr you could use.

甜是你 2024-08-03 17:35:44

首先,我会避免使用 auto_ptr

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

参见此处的示例
或此处

决定语义
foo 的副本是否应该包含对同一 bar 实例的引用? 在这种情况下,请使用 boost::shared_ptr或 (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);
         }
      }
      // ...
   }

First, I'd avoid auto_ptr

Transfer of ownership is good in some scenarios, but I find they are rare, and "full fledged" smart pointer libraries are now available easily. (IIRC auto_ptr was a compromise to include at least one example in the standard library, without the delays that a good implementation would have required).

See, for example here
or here

Decide on semantics
Should the copy of foo hold a reference to the same instance of bar? In that case, use boost::shared_ptr or (boost::intrusive_ptr), or a similar library.

Or should a deep copy be created?
(That may sometimes be required, e.g. when having delay-created state). I don't know any standard implementation of that concept, but it's not to complex to build that similar to existing smart pointers.

   // 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);
         }
      }
      // ...
   }
送舟行 2024-08-03 17:35:44

std::auto_ptr 是管理 C++ 中动态对象的好工具,但为了有效地使用它,了解 auto_ptr 的工作原理非常重要。 本文解释了应使用此智能指针的原因、时间和地点。

对于您的情况,首先您应该决定要如何处理 auto_ptr 中的对象。 应该克隆还是共享?

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

如果需要共享,您应该使用 boost::shared_ptr 正如Martin Liversage建议的那样。

The std::auto_ptr is a good tool for managing dynamic object in C++ but in order to use it effectivelly it's important to unserstand how auto_ptr works. This article explains why, when and where this smart pointer should be used.

In your case, first of all your should decide what you want to do with the object inside your auto_ptr. Should it be cloned or shared?

If it should be cloned, make sure it has a copy constructor and then your create a new auto_ptr which contains a copy of your the object see Adam Badura's answer.

If it should shared, you should use boost::shared_ptr as Martin Liversage suggested.

离去的眼神 2024-08-03 17:35:44

如果我有一个包含 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 成员的可复制类来强加的。

If I have class containing an auto_ptr, and want deep-copy semantics, I generatally only do this for classes that have a virtual copy operator, i.e. clone().

Then, within the copy constructor, I initialize the auto_ptr to a clone() of the other; e.g.

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

clone() is typically implemented as follows:

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

We are imposing the condition that T is clonable, but this condition is essentially imposed by having a copiable class with an auto_ptr member.

來不及說愛妳 2024-08-03 17:35:44

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

由于您无法复制它,因此您也无法复制包含 auto_ptr 的对象。

您可以尝试使用移动语义,例如使用 std::swap 而不是复制。

The whole idea of the auto_ptr is that there's only one owner of the referred to object. This implies you cannot copy the pointer without removing the original ownership.

Since you cannot copy it, you also can't copy an object containing an auto_ptr.

You might try to use move-semantics by e.g. using std::swap instead of copy.

回梦 2024-08-03 17:35:44

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

My first choice would be to avoid auto_ptr in this situation altogether. But if I were backed against a wall, I might try to use the keyword mutable in the declaration of _c - this will allow it to be modified even from a const reference.

油饼 2024-08-03 17:35:44

进行编辑后,您似乎想要转让所有权语义。

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

Given the edit, then it appears you want tranfer of ownership semantics.

In that case, then you'll want to have your copy constructor and assignment operator accept non-const references to their arguments, and perform the initialization/assignment there.

瞳孔里扚悲伤 2024-08-03 17:35:44

您不能在涉及 auto_ptr 的复制构造函数或赋值运算符中使用 const 引用。 删除常量。 换句话说,像

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

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

You can't use const references in a copy constructor or assignment operator that involves an auto_ptr<>. Remove the const. In other words, use declarations like

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

These forms are explicitly mentioned in the Standard, primarily in section 12.8. They should be usable in any standard-conforming implementation. In fact, paragraphs 5 and 10 of 12.8 says that the implicitly defined copy constructor and assignment operator (respectively) will take a non-const reference if any of the members require it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文