只调用了默认构造函数,而不是默认构造函数然后移动构造函数。

huangapple go评论63阅读模式
英文:

Only default constructor was called instead of default construtor then move constructor

问题

我的程序如下:

class X {
public:
    X(int x):m_x(new int{x}) {
        cout << this << '\t';
        cout << "构造函数 X(int x)" << endl;
    } 
    X() {
        cout << this << '\t';
        cout << "构造函数 X()" << endl;
    }
    X(const X& x) {
        cout << this << '\t';
        cout << "构造函数 X(const X&)" << endl;
        cout << "const X& x 的地址 = " << &x << endl;
    }
    X(X&& x) {
        cout << this << '\t';
        cout << "构造函数 X(X&&)" << endl;
        cout << "X&& x 的地址 = " << &x << endl;
        this->m_x = x.m_x;
        x.m_x = nullptr;
    }
    X& operator=(const X& x) {
        cout << this << '\t';
        cout << "= 复制运算符" << endl;
        m_x = x.m_x;
    }
    X& operator=(X&& x) {
        cout << this << '\t';
        cout << "= 移动运算符" << endl;
    }
    X& operator++() {
        cout << this << '\t';
        (*m_x)++;
        cout << "++ 运算符" << endl;
        return *this;
    }
    ~X() {
        cout << this << '\t';
        cout << "析构函数" << endl;
        if(m_x)
            delete m_x;
        else
            cout << "m_x 为空\t";
    }
    int* m_x = nullptr;
};

int main() {
    X x(X{});
}

和输出:

0x7ffcc5a0b150  构造函数 X()
0x7ffcc5a0b150  析构函数
m_x 为空

我认为首先,调用默认构造函数构造X{},然后返回一个右值以构造x,从而调用移动构造函数。但实际上只调用了默认构造函数。

可以有人帮助我理解这个吗?

英文:

My program is as follow:


class X {
public:
    X(int x):m_x(new int{x}) {
        cout &lt;&lt; this &lt;&lt; &#39;\t&#39;;
        cout &lt;&lt; &quot;Constuctor X(int x)&quot;&lt;&lt;endl;

    } 
    X() {
        cout &lt;&lt; this &lt;&lt; &#39;\t&#39;;
        cout &lt;&lt; &quot;Constuctor X()&quot;&lt;&lt;endl;
    }
    X(const X&amp; x) {
        cout &lt;&lt; this &lt;&lt; &#39;\t&#39;;
        cout &lt;&lt; &quot;Constuctor X(const X&amp;)&quot;&lt;&lt;endl;
        cout &lt;&lt; &quot;addr of const X&amp; x = &quot; &lt;&lt; &amp;x &lt;&lt;endl;
        
    }
    X(X&amp;&amp; x)
    {
        cout &lt;&lt; this &lt;&lt; &#39;\t&#39;;
        cout &lt;&lt; &quot;Constuctor X(X&amp;&amp;)&quot;&lt;&lt;endl;
        cout &lt;&lt; &quot;addr of X&amp;&amp; x = &quot; &lt;&lt; &amp;x &lt;&lt;endl;
        this-&gt;m_x = x.m_x;
        x.m_x = nullptr;
    }
    X&amp; operator=(const X&amp; x) {
        cout &lt;&lt; this &lt;&lt; &#39;\t&#39;;
        cout &lt;&lt; &quot;= copy operator&quot;&lt;&lt;endl;
        m_x = x.m_x;
    }
    X&amp; operator=(X&amp;&amp; x){
        cout &lt;&lt; this &lt;&lt; &#39;\t&#39;;
        cout &lt;&lt; &quot;= move operator&quot;&lt;&lt;endl;
    }
    X&amp; operator++(){
        cout &lt;&lt; this &lt;&lt; &#39;\t&#39;;
        *m_x++;
        cout &lt;&lt; &quot;++ operator&quot;&lt;&lt;endl;
        return *this;
    }
    ~X() {
        cout &lt;&lt; this &lt;&lt; &#39;\t&#39;;
        cout &lt;&lt; &quot;Destructor&quot;&lt;&lt;endl;
        if(m_x)
            delete m_x;
        else
            cout &lt;&lt; &quot;m_x null\t&quot;;

    }
    int* m_x = nullptr;
};


int main() {
    X x(X{});
}

And the output:

0x7ffcc5a0b150  Constuctor X()
0x7ffcc5a0b150  Destructor
m_x null 

I think first, default constructor is called to construct X{}, then an rvalue is returned to construct x which calls move constructor. But actualy only default constuctor was called.

Can someone help me to understand this?

答案1

得分: 1

这是因为所谓的复制省略所造成的。

这里发生的是:

  1. 首先,对临时对象的X{}调用使用了默认构造函数,如输出所示。

  2. **现在,由于复制省略,**优化器可以看到临时对象仅在构造函数中使用,而不在其他地方。因此,它优化了代码,跳过了复制构造函数,并在原地构造主要的X对象,使用对象的默认副本,而不必在内存中创建临时对象的副本。

  3. 然后,如输出所示,删除了临时对象。

您可以通过以下方式强制编译器使用您的复制构造函数:

X temp{};
X x(temp);

请注意,大多数情况下,这种优化会导致更好的性能,因为它避免了不必要的复制。

英文:

It happens because of what is called Copy elision.

What is happening here is :

  1. First of all, the call of X{} for the temporary object uses the default constructor as shown in the output

  2. Now, because of Copy Elision, the optimizer can see that the temp object is not used anywhere else that in the constructor by copy. So, it optimizes the code, bypasses the constructor by copy and constructs the main X object in place, using the default copy of objects, instead of having to create a copy of the temp object in the memory.

  3. Then, it deletes the temp object as shown in the output.

You can force the compiler to use your constructor by copy like this :

X temp{}; 
X x(temp);

Note that most of the time, this optimization results in better performances, because it avoids unnecessary copies.

huangapple
  • 本文由 发表于 2023年7月20日 17:32:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76728524.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定