繁体   English   中英

类型是否需要默认构造函数才能声明它的数组?

[英]Does a type require a default constructor in order to declare an array of it?

我注意到,当您声明一个数组时,必须使用默认构造函数。 那正确吗? 有什么例外吗?

例如,

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

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

上面的代码不能编译。

其他答案都可以,但为了完整性:您还可以使用数组初始化语法:

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构造。 在第二个中,初始化列表由用explicit Foo(int) ctor构造的Foo构成,并且数组元素是从初始化列表中的元素复制构造的。 因此在后一种情况下需要Foo的副本。

[1]感谢MSalters的评论。

该问题与数组完全无关。

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

通过在类Foo声明非默认构造函数,您禁用了默认构造函数的隐式生成,因此现在每次创建Foo对象时都必须提供初始化程序,无论它是否是数组元素。

这个宣言

Foo f; // ERROR

不是一个数组,但由于同样的原因它不会编译。 为了编译它,你必须提供一个显式初始化器

Foo f(3); // OK

数组也会发生同样的情况,除了在这种情况下你必须使用聚合初始值设定语法为每个元素提供初始值设定项

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

当然,如果你最终在一个不允许聚合初始化器语法的环境中(在当前版本的C ++标准中),比如构造函数初始化列表或new-expression,那么你确实搞砸了。 在这种情况下,唯一的出路是提供数组元素类型的默认构造函数(只要你坚持使用内置数组)。

该代码无法编译,因为编译器当然不知道您想要传递给每个元素的构造函数。 基本上有两种方法可以解决它:

  1. 使数组成为一个向量,并将所需大小和一个元素传递给它 - 这为每个元素提供了相同的参数。

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

请参阅C ++ FAQ Lite,第10.5

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

“如果你的类没有默认构造函数,那么在尝试创建数组时会出现编译时错误”

但是,更喜欢使用std :: vector而不是内置数组。

没有例外。 在可以看作异常的地方,有一个编译器声明了默认构造函数。

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

例如:

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

// later on...
f[0]->whatever();

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

std::vector <Foo> f;                // OK
std::vector <Foo> f( 5, Foo(0) );   // also OK

不,不。

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

简而言之,它没有任何区别。 您将在创建对象以填充数组时运行构造函数,或者如前所述,当您将其分配给某个东西时(反过来,它会分配空间,运行构造函数)。

警告:稍微偏离主题

如果你有一个没有默认构造函数的类,你绝对需要一个数组,并且你不想进入动态内存分配的开销,你可以使用一个boost :: optionals数组:

boost::optional<Foo> foos[4];  // Stack storage allocated but no objects 
                               // constructed (roughly equivalent to what 
                               // you get with vector<T>::reserve)

if(foos[2]) // Check if the third element has been constructed
{
     foos[2]->bar(); // Access members of Foo with arrow    
}

foos[1] = Foo(1, "a"); // Constructs the second element

foos[1].reset(); // Destroy second element (storage remains there though)

不幸的是,你无法将它传递给期望真正的Foo[]的函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM