编译器优化或我的误解

Val*_*lus 4 c++ oop g++ copy-constructor compiler-optimization

最近我测试了一些C++深度和暗角,我对一个微妙的点感到困惑.我的测试实际上非常简单:

// problem 1
// no any constructor call, g++ acts as a function declaration to the (howmany())
// g++ turns (howmany()) into (howmany(*)()) 
howmany t(howmany());

// problem 2
// only one constructor call
howmany t = howmany();
Run Code Online (Sandbox Code Playgroud)

我对上线的期望是; 第一个howmany()构造函数调用将生成一个临时对象,然后编译器将使用该临时对象和copy-constructor来实例化t.但是,编译器的输出确实让我困惑,因为输出只显示一个构造函数调用.我的朋友们提到了我关于编译器传值优化的问题,但我们对此并不确定.我想了解这里发生了什么?

问题2的输出如下.问题1完全超出了对象实例化,因为编译器将其表现为函数指针声明.

howmany()
~howmany()
Run Code Online (Sandbox Code Playgroud)

我的测试类是:

class howmany {
    public:
        howmany() {
            out << "howmany()" << endl;
        }
        howmany(int i) {
            out << "howmany(i)" << endl;
        }
        howmany(const howmany& refhm) {
            out << "howmany(howmany&)" << endl;
        }
        howmany& operator=(const howmany& refhm) {
            out << "operator=" << endl;
        }
        ~howmany() {
            out << "~howmany()" << endl;
        }
        void print1() {
            cout << "print1()" << endl;
        }
        void print2() {
            cout << "print2()" << endl;
        }
};
Run Code Online (Sandbox Code Playgroud)

Sha*_*our 9

这是最令人头疼的解析:

howmany t( howmany() );
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,你需要添加一组额外的parens:

howmany t( (howmany()) );
           ^         ^
Run Code Online (Sandbox Code Playgroud)

clang 在这里非常有用并警告你:

warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
howmany t( howmany() );
        ^~~~~~~~~~~~~
main.cpp:31:12: note: add a pair of parentheses to declare a variable
howmany t( howmany() );
          ^
          (        )
Run Code Online (Sandbox Code Playgroud)

另一种解决方法是使用C++ 11 统一初始化语法:

howmany t{ howmany{} };
         ^        ^^ ^ 
Run Code Online (Sandbox Code Playgroud)

更新

为了解决2您在问题中添加的部分,标准草案允许在某些情况下省略复制/移动结构.我们可以从12.8 复制和移动类对象31段中看到这一点,它说:

当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用.在这种情况下,实现将省略的复制/移动操作的源和目标视为仅仅两种不同的引用同一对象的方式,并且该对象的销毁发生在两个对象的后期时间.在没有优化的情况下销毁.122在下列情况下,允许复制/移动操作的省略,称为复制省略

并包括以下项目:

当一个未绑定到引用(12.2)的临时类对象被复制/移动到具有相同cv-nonqualified类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的复制/移动

  • @MuratKarakuş等,你改变了问题,现在未来的读者会感到困惑.澄清应作为编辑添加到问题的最后,或者应作为对答案或问题的评论. (2认同)
  • @MuratKarakuş:编辑是为了改善问题,而不是将其改为不同的东西.在这一点上,我只是因为这个答案与上面的问题无关而贬低Shafik! (2认同)