今天当我尝试使用GCC7编译一个非常简单的C ++程序时,我遇到了一个非常奇怪的问题:在没有优化的情况下编译时,程序没有在构造函数中向向量添加任何元素(例如-O0 / -Og)来自Red Hat Enterprise Linux 7上Devtoolset-7的GCC 7.2.1。只有添加了优化开关(例如-O / -O1 / -O2 / ...),编译后的二进制才能生成预期结果。但为什么会这样呢?
顺便说一下:
代码:
#include <vector>
#include <utility>
#include <iostream>
class Container
{
std::vector<std::size_t> elements;
public:
Container() {}
Container(std::size_t n)
{
std::cout << "Creating " << n << " elements:";
for(int i; i<n; ++i)
{
std::cout << " " << i+1;
elements.push_back(i+1);
}
std::cout << '\n';
}
Container(Container& c) : elements{c.elements} {}
Container(Container&& c) : elements{std::move(c.elements)} {}
virtual ~Container() noexcept {}
Container& operator=(const Container& c)
{
if(this != &c)
{
elements = c.elements;
}
return *this;
}
Container& operator=(Container&& c)
{
if(this != &c)
{
elements = std::move(c.elements);
}
return *this;
}
void print()
{
std::cout << "Container has " << elements.size() << " elements:" << '\n';
for(auto it=elements.cbegin(); it!=elements.cend(); ++it)
{
if(it == elements.cbegin()) std::cout << *it;
else std::cout << ", " << *it;
}
if(elements.size()>0) std::cout << '\n';
}
};
Container makeContainer()
{
std::cout << "Inside makeContainer()" << '\n';
std::cout << "Before:" << '\n';
Container c(3);
c.print();
std::cout << "Temporary:" << '\n';
Container c_tmp(3);
c_tmp.print();
c = c_tmp;
std::cout << "After:" << '\n';
c.print();
return c;
};
int main()
{
Container c = makeContainer();
std::cout << "Inside main()" << '\n';
c.print();
return 0;
}
预期产出:
Inside makeContainer()
Before:
Creating 3 elements: 1 2 3
Container has 3 elements:
1, 2, 3
Temporary:
Creating 3 elements: 1 2 3
Container has 3 elements:
1, 2, 3
After:
Container has 3 elements:
1, 2, 3
Inside main()
Container has 3 elements:
1, 2, 3
实际输出:
Inside makeContainer()
Before:
Creating 3 elements:
Container has 0 elements:
Temporary:
Creating 3 elements:
Container has 0 elements:
After:
Container has 0 elements:
Inside main()
Container has 0 elements:
答案 0 :(得分:8)
如果您没有为变量赋值,则其状态是不确定的。
在调试模式下,编译器可以将值零置于初始化不确定值以帮助调试。但是在发布中,这种额外的未初始化不会发生。
for(int i; i<n; ++i) // Here you have declared `i` but not initialized it.
因此,在发布模式下,该值可能大于n
,因此不会插入任何元素。
注意:读取初始化变量的值是UB(因此整个程序可以执行任何操作)。