为什么C++可以使用“fill”初始化可变大小的数组?

5
#include <iostream>
using namespace std;
void aa(int n) {
    int test[n] = {0};
}
int main() {
    aa(10);
    return 0;
}

并获得

error: variable-sized object may not be initialized

但是

#include <iostream>
using namespace std;
void aa(int n) {
    int test[n];
    fill(test,test+10,0);
}
int main() {
    aa(10);
    return 0;
}

可以了

我想知道为什么这个编译通过了,而前面的失败了。


1
你使用的编译器版本是哪个? - Evg
Apple LLVM版本10.0.0(clang-1000.10.44.2)@Evg - jin zhenhui
2
https://onlinegdb.com/SkNQ2eKhB 第一段代码也可以运行。 - Chittaranjan Sethi
两种情况都不合法,因为n不是编译时常量。 - nada
你可能想要使用 std::vectorresize - nada
3个回答

8

VLA不是C++的一部分。它们作为扩展由一些编译器支持。它们来自于C99,在C99中,你不能使用= {0};初始化VLA。一些编译器(如GCC)更进一步并添加了对这种初始化的支持。在GCC中,这种语法可以从版本4.9开始使用。Clang显然不支持它,也不必支持。


1
你只能声明一个大小为常数的数组,这个大小必须在编译时确定。变量n只有在运行时才能确定。
具体来说,在堆栈上分配内存时,大小必须在编译时知道。由于数组是方法的局部变量,它们将被放置在堆栈上。

其实我很好奇为什么我不能在运行时在堆栈上分配变量大小的数组。 - jin zhenhui
我的评论第一行回答了你的问题。 - Maddy
@jinzhenhui,这是C++目前的一个不幸限制。有提案来解决它。 - Evg
1
非常感谢@Evg,这正是我想要的答案。 - jin zhenhui

1

您的两个示例都不合法,因为n不是编译时常量,并且标准C++不允许对数组初始化使用非const长度(但C语言可以)。

您第二个示例之所以能编译,是因为您解决了编译器对第一个示例的唯一问题,即它未初始化。

我建议启用所有编译器警告,这可能应该是默认设置。例如,在GCC中,您可以使用-Wall -Wextra启用它们,还可以选择使用-Werror。如果您希望编译器严格遵循标准,请添加-pedantic

您可能希望改用std::vectorresize。如果是这种情况,您的代码将变成:

#include <vector>

void aa(int n) {
    // 1st parameter: number of elements, 2nd: value of elements.
    std::vector<int> test(n, 0); 
    // test.resize(n, 0); // is also possible
    // std::fill(test.begin(), test.end(), 0); // is also possible
}

int main() {
    aa(10);
    return 0;
}

1
启用警告对第二个示例不会有任何作用。您需要为Clang和GCC使用-pedantic-pedantic-errors标志来诊断使用VLA的情况。 - walnut
谢谢,实际上我只是想知道是否有任何原因使得在运行时在堆栈上分配变量大小的数组成为不可能。 - jin zhenhui
@jinzhenhui 在 https://dev59.com/K3I-5IYBdhLWcg3wYXP8#1887178 中回答了为什么可变长度数组不是标准的 C++。 - nada

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接