You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无拷贝/移动构造函数的类,其std::array作为类成员时如何初始化?

问题:如何初始化包含不可拷贝类的std::array成员的类?

假设有一个无默认构造函数的类A,其拷贝构造函数与拷贝赋值运算符已被显式删除。可以直接创建A的std::array对象(如下方代码中的l_Array),但当该std::array作为另一个类B的成员时,初始化B(如下方代码中的b)会出现编译错误。请问是否可以实现该类的初始化?

代码示例

#include <iostream>
#include <array>

class A
{
public:
    explicit A(int x) : m_x {x} {}
    A(const A &) = delete;
    virtual ~A() {}
    A & operator=(const A &) = delete;
private:
    int m_x;
};

template <std::size_t N>
class B
{
public:
    template <typename ... Types,
              typename std::enable_if_t<sizeof...(Types) == N, int> = 0>
    constexpr explicit B(Types&& ... s) : m_t_Array {static_cast<A>(s)...}
    {
    }
private:
    std::array<A, N> m_t_Array;
};

int main(int, char**) {
    std::array<A, 2> l_Array { A{1}, A{2} };
    B<2> b {A{1}, A{2}};

    return 0;
}

编译错误输出

<source>:21:54: error: static_cast from 'A' to 'A' uses deleted function
    constexpr explicit B(Types&& ... s) : m_t_Array {static_cast<A>(s)...}
                                                     ^~~~~~~~~~~~~~~~~
<source>:30:10: note: in instantiation of function template specialization 'B<2>::B<A, A, 0>' requested here
    B<2> b {A{1}, A{2}};
         ^
<source>:8:5: note: candidate constructor has been explicitly deleted
    A(const A &) = delete;
    ^
1 error generated.

解决方案

问题核心是:直接初始化std::array<A,2>时用的是聚合初始化,会直接在std::array的内存空间里构造每个A对象,不需要拷贝/移动;但你写的B构造函数里,static_cast<A>(s)...会先创建临时A对象,再尝试拷贝到std::array中,触发了被删除的拷贝构造函数。

有两种可行的修复方式:

方式一:完美转发参数给std::array聚合初始化

修改B的构造函数,直接转发参数,让std::array直接构造内部的A对象,避免多余的拷贝:

template <std::size_t N>
class B
{
public:
    template <typename ... Types,
              typename std::enable_if_t<sizeof...(Types) == N, int> = 0>
    constexpr explicit B(Types&& ... s) : m_t_Array { std::forward<Types>(s)... }
    {
    }
private:
    std::array<A, N> m_t_Array;
};

这里std::forward会保持参数的右值/左值属性,std::array的聚合初始化会直接用传入的参数在自身内存中构造A实例,完全绕过拷贝构造。

方式二:使用定位new直接构造

如果希望支持用原始值(比如int)初始化,可以给B添加接受初始化列表的构造函数,通过定位new直接在std::array的内存里构造A:

template <std::size_t N>
class B
{
public:
    constexpr explicit B(std::initializer_list<int> init) 
    {
        static_assert(init.size() == N, "初始化列表长度不匹配");
        std::size_t idx = 0;
        for (int val : init) {
            // 直接在array的对应位置构造A对象
            new (&m_t_Array[idx]) A{val};
            ++idx;
        }
    }
private:
    std::array<A, N> m_t_Array;
};

使用时可以直接写B<2> b {1, 2};,同样不会触发拷贝构造。

两种方式都能正常通过编译,核心都是避免拷贝操作,直接在std::array的内存空间中构造A对象。

内容的提问来源于stack exchange,提问作者Guillaume BERLAND

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 03:15:50