如何通过复制构造函数复制内置数组?

Ita*_*iwa 0 c++ arrays copy-constructor

我们知道内置数组既不能复制也不能赋值。因此,如果它是类/结构/联合的成员数据,则可以让编译器发挥其魔力来复制它们:

struct ArrInt5{
    ArrInt5() = default;
    ArrInt5(ArrInt5 const&) = default; // OK 
    int a[5];
};

ArrInt5 a, b = a; // OK
Run Code Online (Sandbox Code Playgroud)
  • 有时情况并非如此,例如,如果数组包含非默认可构造对象的对象。在这种情况下,我们确实需要定义复制因子来完成这项工作:

      struct Bar{
          // deleted default ctor
          Bar(int x) : x_(x){}
          int x_ = 0;
      };
    
      struct Foo{
          Foo();
          Foo(Foo const&);
    
          Bar arr_[5];
      };
    
      Foo::Foo() : arr_{0, 1, 2, 3, 4}
      {}
    
      Foo::Foo(Foo const& rhs) : arr_{rhs.arr_[0], rhs.arr_[1], rhs.arr_[2], rhs.arr_[3], rhs.arr_[4]}
      {}
    
    Run Code Online (Sandbox Code Playgroud)
  • 正如您所看到的,Foo有一个由五个类型的对象组成的内置数组,struct Bar该类型不可默认构造,因此默认构造函数和复制构造函数必须对其进行初始化(arr_)。

  • 问题是:如果数组很大(比如 100 万个元素),如何初始化该数组?我应该逐个元素地硬复制它们吗?或者有一些解决方法?

    • 我知道很多人会推荐我使用等效的 STL 容器,std::array但我不讨论这个主题,我想问是否有针对我的内置非默认可构造对象数组的解决方法。

Hum*_*ler 5

自动生成此效果的唯一方法是将数组包装在某种具有编译器生成的复制构造函数(例如 eddefault构造函数)的类类型中。在您的特定示例中,您可能只是被Foo(const Foo&)编辑default

struct Foo{
    Foo();
    Foo(Foo const&) = default;
    // This generates your:
    // "Foo::Foo(Foo const& rhs) : arr_{rhs.arr_[0], rhs.arr_[1], rhs.arr_[2], rhs.arr_[3], rhs.arr_[4]}"
    // by the compiler

    Bar arr_[5];
};
Run Code Online (Sandbox Code Playgroud)

然而,只有当您的复制逻辑很简单时,上述方法才有效。对于更复杂的复制,你不能总是有一个default复制构造函数——但我们可以更普遍地解决这个问题。

如果将任何类型/大小的数组数据成员包装在 or 中structclass并确保它具有编译器生成的复制构造函数,则在构造函数中复制很容易。

例如:

struct Foo{
    Foo();
    Foo(Foo const&) = default;
    // This generates your:
    // "Foo::Foo(Foo const& rhs) : arr_{rhs.arr_[0], rhs.arr_[1], rhs.arr_[2], rhs.arr_[3], rhs.arr_[4]}"
    // by the compiler

    Bar arr_[5];
};
Run Code Online (Sandbox Code Playgroud)

这允许简单的复制情况:

template <typename T, std::size_t N>
struct Array {
  ...
  T data[N];
};
Run Code Online (Sandbox Code Playgroud)

或者在构造函数中进行复制的更复杂的情况可能需要比编译器生成的逻辑更多的逻辑:

Array<Bar,1000000> a = {{...}};
Array<Bar,1000000> b = a; 
Run Code Online (Sandbox Code Playgroud)

此时,恭喜你——你发明了std::arraystd::array之所以被添加到标准库中,正是因为引入一个库解决方案来解决这个问题非常简单,而无需改变语言本身。不要回避它。