所以我遇到了一些奇怪的行为,我将其简化为以下最小示例:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec;
for(int i = 0; i < 1000; i++)
{
vec.push_back(2150000 * i);
if(i % 100 == 0) std::cout << i << std::endl;
}
}
使用命令使用gcc 7.3.0编译时
c++ -Wall -O2 program.cpp -o program
我没有任何警告。运行该程序将产生以下输出:
0
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
[ snip several thousand lines of output ]
1073741600
1073741700
1073741800
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
我猜这意味着我终于为该向量耗尽了内存。
很显然,这里有问题。我猜这与2150000 * 1000略大于2 ^ 31有关,但这并不是那么简单-如果我将此数字减小为2149000,则程序将按预期运行:
0
100
200
300
400
500
600
700
800
900
cout
对于重现此行为不是必需的,因此我认为实际上是一个最小的例子
#include <vector>
int main()
{
std::vector<int> vec;
for(int i = 0; i < 1000; i++)
{
vec.push_back(2150000 * i);
}
}
运行此命令会使程序等待很长时间,然后崩溃。
问题
无论从哪方面来讲,我对C ++都是陌生的。我是否在做一些愚蠢的事情,允许出现未定义的行为?还是这是gcc
中的错误?
我确实尝试过使用Google,但是我真的不知道该怎么做。
附录
我看到(带符号的)整数溢出是C ++中的未定义行为。据我了解,这仅表示表达式的行为
21500000 * i
是不确定的-即它可以求值为任意数字。也就是说,我们可以看到该表达式至少没有改变i
的值。
答案 0 :(得分:5)
要回答我自己的问题,在检查了汇编程序输出后,看起来g ++通过更改
优化了该循环。for(int i = 0; i < 1000; i++)
{
vec.push_back(2150000 * i);
}
类似
for(int j = 0; j < 1000 * 2150000; j += 2150000)
{
vec.push_back(j);
}
我想加法要比每个周期进行乘法快,并且关于溢出是未定义行为的规则意味着可以进行此更改,而不必担心计算溢出时是否会引入意外行为。
当然,优化循环中的条件总是失败,所以最终我最终得到了类似的东西
for(int j = 0; true; j += 2150000)
{
vec.push_back(j);
}