C++ std::shared_ptr的唯一副本

C++ std::shared_ptr的唯一副本,c++,c++11,C++,C++11,我有一个对象(我们称之为X),其他对象可以通过std::shared\u ptr访问它。但是,在某些情况下,这些对象需要创建一个唯一的、非共享的X副本,因为它想要修改它。这在某种程度上类似于写时复制,但由于其他一些细节的原因,并不完全相同 基本上,我希望有这样的语义: struct Foo { std::shared_ptr<Bar> bar; void go() { // bar.use_count() >= 1 bar.make_this_obj

我有一个对象(我们称之为X),其他对象可以通过
std::shared\u ptr
访问它。但是,在某些情况下,这些对象需要创建一个唯一的、非共享的X副本,因为它想要修改它。这在某种程度上类似于写时复制,但由于其他一些细节的原因,并不完全相同

基本上,我希望有这样的语义:

struct Foo
{
  std::shared_ptr<Bar> bar;
  void go()
  {
    // bar.use_count() >= 1
    bar.make_this_object_unique();
    // bar.use_count() == 1
  }
}
structfoo
{
std::共享的ptr条;
void go()
{
//bar.use_count()>=1
bar.make_this_object_unique();
//bar.use_count()==1
}
}

您可以执行以下操作

bar = shared_ptr<Bar>(new Bar(*bar));
bar=shared_ptr(新条(*bar));

您需要做的是在基础对象上执行正确的复制,因为让两个共享的\u ptr实例管理同一个内存是行不通的。

如果您只是想复制对象,并获取指向新对象的共享指针,那么这就行了

bar = std::make_shared<Bar>(*bar);

您可能需要测试bar.unique(),以确定是否需要复制。

在一般情况下不可能。可能有两种情况:

  • 存储在bar中的对象是bar类型,而不是从bar继承的类。然后只需使用复制构造函数(前提是它可用):

    bar=std::使_共享(*bar)

  • Bar或其任何基类以创建新分配副本的虚拟函数的形式提供克隆功能:

    bar=std::shared_ptr(bar->Clone())

  • 您甚至可以直接使用它,如
    cow\u ptr(bar)->blah()


    cow
    代表“写时复制”
    cow_ptr
    代表“moo”。

    你的意思是
    bar=std::make_shared(*bar),为从旧对象复制的新对象提供(唯一)共享指针?还是我错过了什么?@MikeSeymour他不能这样做,因为那样会有两个共享的\u ptr实例监视同一个指针。它们中的任何一个都可能删除该资源。您将如何使保存该资源的其他共享指针无效?@sbaker:不,不会
    make_shared
    将创建一个新对象,复制旧对象,并返回指向该对象的共享指针。现有指针仍将管理旧对象。抱歉@MikeSeymour,你是对的。我需要更仔细地阅读——我想我读的是共享的,而不是共享的。谢谢。这与我到目前为止使用的C++11之前的指针类的语义有所不同,但似乎是合理的。最后一件事——如果对象已经是唯一的,我如何避免复制它?
    struct Bar {
        virtual std::shared_ptr<Bar> clone() = 0;
    };
    
    struct SomeKindOfBar : Bar {
        virtual std::shared_ptr<Bar> clone() {
            return std::make_shared<SomeKindOfBar>(*this);
        }
    };
    
    bar = bar->clone();
    
    template<typename T>
    std::shared_ptr<T>& cow_ptr( std::shared_ptr<T>& t ) {
      if (t && !t.unique())
        t = std::make_shared<T>( *t );
      return t;
    }
    
    struct Foo
    {
      std::shared_ptr<Bar> bar;
      void go()
      {
        cow_ptr(bar);
      }
    }