C++ 类型是否需要默认构造函数才能声明其数组?

C++ 类型是否需要默认构造函数才能声明其数组?,c++,arrays,constructor,C++,Arrays,Constructor,我注意到,在声明数组时,必须使用默认构造函数。是这样吗? 有例外吗 比如说, struct Foo{ Foo(int i ) {} }; int main () { Foo f[5]; return 0; } 上面的代码无法编译 也不例外。在可以被视为异常的情况下,有一个编译器声明为默认构造函数。是的,您在这里需要默认构造函数,因为Foo f[5]实际创建了5个Foos。您可以通过将其设置为Foo*f[5]然后使用new创建5Foos来解决此问题 例如: Foo* f[5]

我注意到,在声明数组时,必须使用默认构造函数。是这样吗? 有例外吗

比如说,

struct Foo{
Foo(int i  ) {}
};

int main () {
    Foo f[5];
    return 0;
}

上面的代码无法编译

也不例外。在可以被视为异常的情况下,有一个编译器声明为默认构造函数。

是的,您在这里需要默认构造函数,因为
Foo f[5]实际创建了5个
Foo
s。您可以通过将其设置为
Foo*f[5]
然后使用
new
创建5
Foo
s来解决此问题

例如:

Foo* f[5];
for(int i = 0; i < 5; ++i) {
    f[i] = new Foo(i);
}

// later on...
f[0]->whatever();
Foo*f[5];
对于(int i=0;i<5;++i){
f[i]=新的Foo(i);
}
//后来。。。
f[0]->whatever();

该代码不会编译,因为编译器当然不知道要传递给每个元素的构造函数的内容。基本上有两种方法:

  • 将数组设为向量,并将所需大小加上一个元素传递给它——这将为每个元素提供相同的参数

  • 使数组成为指针数组,并使用for循环和new运算符构造每个元素。当然,缺点是以后还必须释放每个元素


  • 参见C++ FAQ Lite,章节

    创建数组时,会为数组中的每个元素调用默认构造函数

    如果您的类没有默认构造函数,则在尝试创建数组时会出现编译时错误


    不过,您更愿意使用std::vector而不是内置数组。

    其他答案也可以,但为了完整起见,您也可以使用数组初始化语法:

    Foo f[5] = {1,2,3,4,5};
    
    如果Foo的ctor不是显式的,那么这是有效的。如果是的话,你就得。。。。明确的:

    Foo f[5] = {Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)};
    
    注意1:这两种情况之间的差异可能并不明显,因此值得注意:首先,通过调用
    Foo(int)
    ctor,从初始化列表中的
    int
    s直接构造数组元素。在第二种情况下,初始化列表由使用
    显式Foo(int)
    ctor构造的
    Foo
    s组成,数组元素是从初始化列表中的元素复制构造的。因此,在后一种情况下,需要一个Foo的副本


    [1] 感谢MSalters的评论。

    请注意,如果使用
    std::vector
    而不是数组,则不需要默认构造函数-您可以指定要使用的构造函数:

    std::vector <Foo> f;                // OK
    std::vector <Foo> f( 5, Foo(0) );   // also OK
    
    std::vector f;//好啊
    向量f(5,Foo(0));//也可以
    
    警告:有点离题

    如果您有一个没有默认构造函数的类,那么您绝对需要一个数组,并且您不想导致动态内存分配的开销,您可以使用以下数组:

    boost::可选的foos[4];//已分配堆栈存储,但没有对象
    //构造(大致相当于什么
    //您可以使用vector::reserve获得
    if(foos[2])//检查是否构造了第三个元素
    {
    foos[2]->bar();//使用箭头访问Foo的成员
    }
    foos[1]=Foo(1,“a”);//构造第二个元素
    foos[1]。重置();//销毁第二个元素(但存储仍然存在)
    

    不幸的是,您将无法将此消息传递给一个需要真正的
    Foo[]

    的函数。该问题与数组无关

    默认初始化类类型的对象时,需要默认构造函数。如果您的类没有默认构造函数,那么在创建该类的对象时,除了提供显式初始值设定项之外,您别无选择。就这些

    通过在类
    Foo
    中声明一个非默认构造函数,您禁用了默认构造函数的隐式生成,因此现在您必须在每次创建
    Foo
    对象时提供一个初始值设定项,无论它是否为数组元素

    本声明

    Foo f; // ERROR
    
    不是数组,但出于同样的原因,它不会编译。为了编译它,您必须提供一个显式的初始值设定项

    Foo f(3); // OK
    
    数组也会发生同样的情况,只是在这种情况下,必须使用聚合初始值设定项语法为每个元素提供一个初始值设定项

    Foo f[5] = { 1, 2, 3, 4, 5 };
    

    当然,如果最终在不允许聚合初始化语法的情况下(在C++标准的当前版本中),像构造函数初始化列表或新表达式,那么您确实被拧紧了。在这种情况下,唯一的解决办法是在数组元素类型中提供默认构造函数(只要您坚持使用内置数组)。

    不,它没有

    在C/C++中,数组是一个内存块。创建数组就是保留该块。创建对象是“1.分配空间2.在每个块上运行构造函数”,因此,如果您有一个没有构造函数的对象,您仍然可以创建它的数组(因为该对象有一个大小,并且内存理解“大小”)


    简言之,这没有任何区别。当您创建要填充数组的对象时,或者如前所述,当您将数组分配给某个对象时(该对象分配空间,运行构造函数),您将运行构造函数。

    第二个示例需要一个可用的复制构造函数,特别是一个可以复制临时对象的复制构造函数。您在创建
    auto_ptr
    s数组时仍然会遇到问题。@MSalters:谢谢您的宝贵意见。我在答案上加了一条注释。此外,你怎么能有一个“没有构造函数的对象”?这根本没有意义——类有构造函数,所有类都至少有一个构造函数。如果你不声明一个,编译器会。
    Foo f[5] = { 1, 2, 3, 4, 5 };