You need to enable JavaScript to run this app. 如何通过拷贝构造函数复制作为类成员的内置数组
优惠活动
大模型
产品
解决方案
定价
更多

如何通过拷贝构造函数复制作为类成员的内置数组

解决方案

方案1:编译期索引序列+委托构造(通用无运行时开销,首推)

这是最稳妥的实现方式,所有逻辑在编译期完成,和手动逐个写初始化列表的性能完全一致,支持任意非默认可构造类型,不会触发未定义行为。

C++14 及以上版本实现

直接用标准库提供的std::index_sequence即可:

#include <utility>

struct Bar{
    Bar(int x) : x_(x){}
    int x_ = 0;
};

constexpr size_t ARR_SIZE = 1000000; // 数组大小可自行修改
struct Foo{
    Foo();
    Foo(Foo const& rhs);

    Bar arr_[ARR_SIZE];

private:
    // 私有委托构造函数,接收编译期索引序列
    template <std::size_t... Idx>
    Foo(Foo const& rhs, std::index_sequence<Idx...>) : arr_{rhs.arr_[Idx]...} {}
    // 给默认构造用的委托构造
    template <std::size_t... Idx>
    Foo(std::index_sequence<Idx...>) : arr_{Idx...} {}
};

// 默认构造不需要手写0到999999的初始化项
Foo::Foo() : Foo(std::make_index_sequence<ARR_SIZE>{}) {}

// 拷贝构造自动生成所有元素的初始化项
Foo::Foo(Foo const& rhs) : Foo(rhs, std::make_index_sequence<ARR_SIZE>{}) {}

C++11 兼容实现

C++11 标准库没有提供std::index_sequence,自行实现一个极简版本即可使用,逻辑和上面完全一致:

#include <cstddef>

// 自实现index_sequence兼容C++11
template <std::size_t... Is>
struct index_sequence {};

template <std::size_t N, std::size_t... Is>
struct make_index_sequence_impl : make_index_sequence_impl<N-1, N-1, Is...> {};

template <std::size_t... Is>
struct make_index_sequence_impl<0, Is...> {
    using type = index_sequence<Is...>;
};

template <std::size_t N>
using make_index_sequence = typename make_index_sequence_impl<N>::type;

// 后续Bar和Foo的实现和C++14版本完全一致
struct Bar{
    Bar(int x) : x_(x){}
    int x_ = 0;
};

constexpr size_t ARR_SIZE = 1000000;
struct Foo{
    Foo();
    Foo(Foo const& rhs);

    Bar arr_[ARR_SIZE];

private:
    template <std::size_t... Idx>
    Foo(Foo const& rhs, index_sequence<Idx...>) : arr_{rhs.arr_[Idx]...} {}

    template <std::size_t... Idx>
    Foo(index_sequence<Idx...>) : arr_{Idx...} {}
};

Foo::Foo() : Foo(make_index_sequence<ARR_SIZE>{}) {}

Foo::Foo(Foo const& rhs) : Foo(rhs, make_index_sequence<ARR_SIZE>{}) {}

注意事项

如果数组大小超过编译器默认的模板递归深度(GCC默认是900,Clang默认是1024),编译时需要额外加参数调整递归深度,比如GCC下加:
-ftemplate-depth=1000010(数值比数组大小略大即可)

方案2:手动 placement new 构造(仅适用于特殊场景)

如果你的编译器对大长度索引序列的编译速度太慢,且你的类型是平凡可拷贝的(可以用std::is_trivially_copyable_v<Bar>验证),可以用下面的方案:

#include <cstring>
#include <type_traits>

struct Bar{
    Bar(int x) : x_(x){}
    int x_ = 0;
};
static_assert(std::is_trivially_copyable_v<Bar>, "Bar必须是平凡可拷贝类型才能用该方案");

constexpr size_t ARR_SIZE = 1000000;
struct Foo{
    Foo();
    Foo(Foo const& rhs);
    ~Foo(); // 非平凡析构需要手动实现

    // 用char数组占坑,手动管理对象生命周期
    alignas(Bar) char arr_storage_[sizeof(Bar) * ARR_SIZE];

    // 提供arr_的访问接口,兼容原有代码
    Bar* arr_() { return reinterpret_cast<Bar*>(arr_storage_); }
    Bar const* arr_() const { return reinterpret_cast<Bar const*>(arr_storage_); }
};

Foo::Foo() {
    for (size_t i = 0; i < ARR_SIZE; ++i) {
        new (arr_() + i) Bar(i);
    }
}

Foo::Foo(Foo const& rhs) {
    std::memcpy(arr_storage_, rhs.arr_storage_, sizeof(arr_storage_));
}

Foo::~Foo() {
    for (size_t i = 0; i < ARR_SIZE; ++i) {
        arr_()[i].~Bar();
    }
}

警告:该方案仅适用于平凡可拷贝类型,非平凡类型用memcpy拷贝会直接触发未定义行为,且需要手动管理对象的构造析构,风险较高,非必要不推荐使用。


内容的提问来源于stack exchange,提问作者Itachi Uchiwa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 23:39:03