rvalue作为初始化程序来构造对象

rvalue as initialiser to construct an object

本文关键字:对象 程序 初始化 rvalue      更新时间:2023-10-16

我是编程新手。抱歉我英语不好。我试着用右值作为初始化对象的初始化器。因此,根据代码,它将打印出使用的构造函数和赋值运算符。但结果是对象"what2"answers"what3",它们不会打印出任何东西。这是代码:

#include <iostream>
using namespace std;
class X{
public:
    int x;
    X()= default;
    X(int num):x{num}{}
    X(const X& y){
        x = y.x;
        std::cout << "copy constructor" << std::endl;
        std::cout << x << std::endl;
    }
    X& operator=(const X& d){
        x = d.x;
        std::cout << "copy assignment" << std::endl;
        return *this;
    }
    X(X&& y){
        x = y.x;
        std::cout << "move constructor" << std::endl;
    }
    X& operator=(X&& b){
        x = b.x;
        std::cout << "move assignment" << std::endl;
        return *this;
    }
};
X operator +(const X& a,const X& b){
    X tmp{};
    tmp.x = a.x +b.x;
    return tmp;
}
int main(int argc, const char * argv[]) {
    X a{7} , b{11};
    X what1;
    cout << "---------------" << endl;
    what1 = a+b;
    cout << "---------------" << endl;
    X what2{a+b};
    cout << "---------------" << endl;
    X what3 = a+b;
    cout << "---------------" << endl;
    std::cout << what1.x << std::endl;
    std::cout << what2.x << std:: endl;
    std::cout <<what3.x << std::endl;
    return 0;
}

输出为:

---------------
move assignment
---------------
---------------
---------------
18
18
18
Program ended with exit code: 0

只有"what1"正确使用赋值。那么,我如何使用右值来初始化一个对象呢?并使用运算符=初始化对象?非常感谢。

您的代码可能会导致正在使用的移动操作,但您的编译器已选择取消这些移动,并直接在调用站点分配operator+的返回。如果在编译器中禁用复制省略(GCC或Clang中的-fno-elide-constructors),则可以看到这种情况。

您的移动构造函数和赋值运算符将成功用于不允许复制省略的上下文,例如:

X what2 { std::move(what1) }; //can't elide copy, move constructor used

下面的代码会触发更多的构造函数/运算符,请查看在什么情况下是哪个触发器

#include <iostream>
using namespace std;
class X{
public:
    int x;
    X()
    {
        x = 0;
        std::cout << "constructor" << std::endl;
    }
    X(int num):x{num}
    {
        std::cout << "list initilizer" << std::endl;
    }
    X(const X& y){
        x = y.x;
        std::cout << "copy constructor" << std::endl;
    }
    X& operator=(const X& d){
        x = d.x;
        std::cout << "copy assignment" << std::endl;
        return *this;
    }
    X(X&& y){
        x = y.x;
        std::cout << "move constructor" << std::endl;
    }
    X& operator=(X&& b){
        x = b.x;
        std::cout << "move assignment" << std::endl;
        return *this;
    }
};
X operator +(const X& a,const X& b){
    X tmp{};
    tmp.x = a.x +b.x;
    return tmp;
}
int main(int argc, const char * argv[]) {
    X a{7} , b{11};
    cout << "---------------" << endl;
    X what1;
    cout << "---------------" << endl;
    what1 = a+b;
    cout << "---------------" << endl;
    X what2(a+b);
    cout << "---------------" << endl;
    X what3 = X(a);
    cout << "---------------" << endl;
    X what4 = X();
    cout << "---------------" << endl;
    X what5 = std::move(what1);
    cout << "---------------" << endl;
    what5 = std::move(what1);
    cout << "---------------" << endl;
    what5 = what1;
    cout << "---------------" << endl;
    return 0;
}

GCC提供了-fno-elide-constructors选项以禁用复制省略。如果要消除复制省略,请使用flag-fno-elide构造函数。参考https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization/27916892#27916892有关更多详细信息,