C++11 是否有可能拥有一个可复制的可构造类来保存std::unique\u ptr<;基地>;避免在不暴露基底的情况下进行切片;克隆;功能?

C++11 是否有可能拥有一个可复制的可构造类来保存std::unique\u ptr<;基地>;避免在不暴露基底的情况下进行切片;克隆;功能?,c++11,copy-constructor,smart-pointers,move-semantics,deep-copy,C++11,Copy Constructor,Smart Pointers,Move Semantics,Deep Copy,有没有一种方法可以为类(例如,Copyable)编写一个复制构造函数,该类将std::unique_ptr保存到基类(但实际上是存储派生的对象) 快速测试显示出现了预期的切片,因为Copyable不知道它所持有的实际类型。因此我认为需要一个clone方法,但我想知道是否有一种方法可以让编译器以更好的方式处理这个问题 切片代码: #include <algorithm> #include <iostream> #include <memory> struct B

有没有一种方法可以为类(例如,
Copyable
)编写一个复制构造函数,该类将
std::unique_ptr
保存到
类(但实际上是存储
派生的
对象)

快速测试显示出现了预期的切片,因为
Copyable
不知道它所持有的实际类型。因此我认为需要一个
clone
方法,但我想知道是否有一种方法可以让编译器以更好的方式处理这个问题

切片代码:

#include <algorithm>
#include <iostream>
#include <memory>
struct Base
{
  Base(int i = 0) : i(i) {}
  virtual ~Base() = default;
  int i;
  virtual int f() { return i; }
};

struct Derived : Base
{
  Derived() = default;
  virtual int f() override { return 42; }
};

struct Copyable
{
  Copyable(std::unique_ptr<Base>&& base) : data(std::move(base)) {}
  Copyable(const Copyable& other)
  {
    data = std::make_unique<Base>(*other.data);
  }
  std::unique_ptr<Base> data;
};

int main()
{
  Copyable c(std::make_unique<Derived>());
  Copyable c_copy = c;

  std::cout << c_copy.data->f() << '\n';
}
显然,克隆代码是有效的。问题是,其中有些东西我想避免:

  • 原始
  • 需要作为接口一部分的随机函数
  • 此函数返回一个原始指针
  • 此类中希望可复制的每个用户都需要调用此函数
  • 那么,有没有“干净”的替代方案


    注:出于所有明显的原因,我想使用智能指针,我只需要一个深度复制
    std::unique_ptr
    。类似于
    std::copyable_unique_ptr
    ,将可选移动语义与深度复制构造函数相结合。这是最干净的方法吗?还是只会增加混乱?

    您当然可以创建一个
    clone\u ptr
    -为静态地知道如何克隆的任何对象初始化


    它将包含一个指向对象的指针,以及一个指向用于克隆所述对象的函数的指针,可能来自转换无状态lambda。

    您当然可以为静态地知道如何克隆的任何对象创建一个
    clone\u ptr
    -类


    它将包含一个指向对象的指针,以及一个指向用于克隆所述对象的函数的指针,可能来自转换无状态lambda。

    a
    std::copyable_unique_ptr
    没有意义。拥有一个指向可克隆对象的
    std::unique_ptr
    更有意义。您拥有的可能是最好的方法。有不过有两点:复制构造函数是一个构造函数,因此它可以有一个成员初始化列表。
    clone
    函数应该调用复制构造函数,复制
    *这个
    。派生类中的
    clone
    函数应该返回一个指向基类的指针。@Someprogrammerdude
    可复制函数如何运行ique_ptr
    毫无意义?有很多情况下,双方都希望在需要时移动和复制数据。当然,您需要小心使用
    std::move
    ,但复制仅移动的类型而不弄脏接口似乎意味着这是一个明智的解决方案。@rubenvb复制构造的危险当用户不希望调用TOR时,调用TOR是不赞成使用
    auto\u ptr
    的一个重要原因。使用
    copyable\u unique\u ptr
    ,效果会稍微好一点,但仍然不好。
    clonable\u unique\u ptr
    (或
    clone\u ptr
    ,就像重复数据消除程序的答案一样)它不提供复制构造函数,但提供了
    clone()
    member函数,实现了您希望通过
    copyable\u unique\u ptr
    实现的功能,但没有危险。发生深度复制而不是移动的危险?我更喜欢使用
    copyable\u unique\u ptr
    生成类的默认复制/移动构造函数,而不是单独的克隆函数。但我同意这是一个折衷。嗯,似乎不可能让一个
    copyable\u unique\u ptr
    正确地创建一个副本,而它的指针实际上是
    派生的
    。一个
    std::copyable\u unique\u ptr
    没有意义。有一个指向可克隆对象的
    std::unique\u ptr
    更有意义。你拥有的可能是最好的方法。有一个耦合但是要点之一:复制构造函数是一个构造函数,因此它可以有一个成员初始化列表。
    clone
    函数应该调用复制构造函数,复制
    *这个
    。派生类中的
    clone
    函数应该返回一个指向基类的指针。@Someprogrammerdude
    可复制函数如何唯一_ptr
    毫无意义?在很多情况下,双方都希望在需要时移动和复制数据。当然,您需要小心使用
    std::move
    ,但复制仅移动的类型而不弄脏接口似乎意味着这是一个明智的解决方案。@rubenvb复制构造函数的危险性在用户不期望的情况下被调用是
    auto\u ptr
    被弃用的一个重要原因。使用
    copyable\u unique\u ptr
    ,效果会稍微好一点,但仍然不好。
    clonable\u unique\u ptr
    (或
    clone\u ptr
    与重复数据消除程序的答案一样)它不提供复制构造函数,但提供了
    clone()
    member函数,实现了您希望通过
    copyable\u unique\u ptr
    实现的功能,但没有危险。发生深度复制而不是移动的危险?我更喜欢使用
    copyable\u unique\u ptr
    生成类的默认复制/移动构造函数,而不是单独的克隆函数。但我同意这是一个折衷。嗯,似乎不可能让
    可复制的\u unique\u ptr
    在其指针实际是
    派生的
    时正确创建副本。
    #include <algorithm>
    #include <iostream>
    #include <memory>
    struct Base
    {
      Base(int i = 0) : i(i) {}
      virtual ~Base() = default;
      int i;
      virtual int f() { return i; }
    
      virtual Base* clone() { return new Base(i); }
    };
    
    struct Derived : Base
    {
      Derived() = default;
      virtual int f() override { return 42; }
    
      virtual Derived* clone() override { return new Derived(); }
    
    };
    
    struct Copyable
    {
      Copyable(std::unique_ptr<Base>&& base) : data(std::move(base)) {}
      Copyable(const Copyable& other)
      {
        data.reset(other.data->clone());
      }
      std::unique_ptr<Base> data;
    };
    
    int main()
    {
      Copyable c(std::make_unique<Derived>());
      Copyable c_copy = c;
    
      std::cout << c_copy.data->f() << '\n';
    }