GCC没有优化编译的简单C ++程序不能生成预期结果

时间:2018-03-26 23:01:43

标签: c++ gcc

今天当我尝试使用GCC7编译一个非常简单的C ++程序时,我遇到了一个非常奇怪的问题:在没有优化的情况下编译时,程序没有在构造函数中向向量添加任何元素(例如-O0 / -Og)来自Red Hat Enterprise Linux 7上Devtoolset-7的GCC 7.2.1。只有添加了优化开关(例如-O / -O1 / -O2 / ...),编译后的二进制才能生成预期结果。但为什么会这样呢?

顺便说一下:

  1. 没有优化,由GCC 7.2.1在RHEL7上编译的二进制文件和在Mac上的GCC 7.3.0(Homebrew版本)表现不同:前者没有添加任何元素,而后者添加2个元素。
  2. 无论优化是否开启,
  3. clang都没有这个问题)
  4. 代码:

    #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:
    

1 个答案:

答案 0 :(得分:8)

如果您没有为变量赋值,则其状态是不确定的。

在调试模式下,编译器可以将值零置于初始化不确定值以帮助调试。但是在发布中,这种额外的未初始化不会发生。

    for(int i; i<n; ++i)  // Here you have declared `i` but not initialized it.

因此,在发布模式下,该值可能大于n,因此不会插入任何元素。

注意:读取初始化变量的值是UB(因此整个程序可以执行任何操作)。