标准::shared_ptr的唯一副本

Unique copy of std::shared_ptr

本文关键字:唯一 副本 shared 标准 ptr      更新时间:2023-10-16

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

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

struct Foo
{
  std::shared_ptr<Bar> bar;
  void go()
  {
    // bar.use_count() >= 1
    bar.make_this_object_unique();
    // bar.use_count() == 1
  }
}

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

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

这假定Bar是目标的实际类型。如果要复制 Bar 的任意子类,则需要一个虚函数来复制对象,例如:

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();

您可能需要测试bar.unique()以确定是否需要副本。

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

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

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

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

    bar = std::shared_ptr<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;
}

为您提供T的写入复制。 如果它实际上不是T,这将切片t

用途是:

struct Foo
{
  std::shared_ptr<Bar> bar;
  void go()
  {
    cow_ptr(bar);
  }
}

您甚至可以直接使用它,例如 cow_ptr(bar)->blah() .

cow 代表"写入时复制"。 cow_ptr代表"哞哞"。

你可以

做类似的事情

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

您需要做的是对基础对象执行正确的复制,因为让两个shared_ptr实例管理相同的内存是行不通的。