如果函数返回值类型是右值引用,并且返回的是函数内部的局部变量,会如何

省流:不管看起来好像fun里面的局部变量a好像被“移动“出来了,但a在除了它所在的作用域后立刻就释放了,move出来的变量已经指向了“空悬”的对象。再访问的话程序将产生不可预知行为。

struct DPoint3d
{
    //! x coordinate
    double x;
    //! y coordinate
    double y;
    //! z coordinate
    double z;

    DPoint3d() = default;
    ~DPoint3d()
    {
        std::cout << "~DPoint3d" << endl;
    }
    DPoint3d(const DPoint3d& pt)
    {
        std::cout << "123" << endl;
        x = pt.x;
        y = pt.y;
        z = pt.z;
    }

    DPoint3d(const DPoint3d&& pt)
    {
        std::cout << "456" << endl;
        x = pt.x;
        y = pt.y;
        z = pt.z;
    }

    DPoint3d& operator=(DPoint3d&& pt) {
        std::cout << "789" << endl;
        x = pt.x;
        y = pt.y;
        z = pt.z;
    }
};

DPoint3d&& fun()
{
    DPoint3d a; // 默认构造
    a.x = 1;
    a.y = 2;
    a.z = 3;
    // return a; // 报错:无法将左值绑定到右值引用
    return std::move(a); // 返回右值引用,没有进行构造
}


int main()
{    
    DPoint3d&& a = fun();
    std::cout << a.x << endl;    
}

编译成功,可以运行,但这种代码是有问题的:

刚执行完DPoint3d&& a = fun();的时候,调试器还能显示值:

再执行一步,就现出原型了:

 其实,除了fun函数之后,a立刻就析构了:

 

 

 代码改一下,加入移动构造函数。注意第一个DPoint3d&& c = std::move(b);不会调用任何移动构造函数,为什么呢:

struct DPoint3d
{
    //! x coordinate
    double x;
    //! y coordinate
    double y;
    //! z coordinate
    double z;

    DPoint3d() = default;
    DPoint3d(const DPoint3d&& pt)
    {
        x = pt.x;
        y = pt.y;
        z = pt.z;
    }
};

int main()
{
//不会调用到移动构造函数,但c里的值被成功赋值过去了。
        DPoint3d b;
        b.x = 10;
        DPoint3d&& c = std::move(b);

//会调用到移动构造函数
        DPoint3d b;
        b.x = 10;
        DPoint3d c = std::move(b);

//不会调用到移动构造函数
        DPoint3d&& a = fun();
        std::cout << a.x << endl;
}

添加更多的构造函数,还是不会调用到,为什么呢,终于明白,这个地方的c变量,其实就是一个右值引用,属于一个别名。执行之后,c就变成了一个左值,给c的y值赋值,发现b的y值也变了。

那其实这种情况下,DPoint3d&& c = std::move(b);的效果和DPoint3d& c = b;没什么区别了

struct DPoint3d
{
    //! x coordinate
    double x;
    //! y coordinate
    double y;
    //! z coordinate
    double z;

    DPoint3d() = default;
    DPoint3d(const DPoint3d& pt)
    {
        std::cout << "123" << endl;
        x = pt.x;
        y = pt.y;
        z = pt.z;
    }

    DPoint3d(const DPoint3d&& pt)
    {
        std::cout << "456" << endl;
        x = pt.x;
        y = pt.y;
        z = pt.z;
    }

    DPoint3d& operator=(DPoint3d&& pt) {
        std::cout << "789" << endl;
        x = pt.x;
        y = pt.y;
        z = pt.z;
    }
};


int main()
{
    DPoint3d b;
    b.x = 10;
    DPoint3d&& c = std::move(b);
    c.y = 20;
}

 

DPoint3d&& fun()
{
    DPoint3d a; // 默认构造
    a.x = 1;
    a.y = 2;
    a.z = 3;
    // return a; // 报错:无法将左值绑定到右值引用
    //return std::move(a); // 返回右值引用,没有进行构造
    return a; // 返回右值引用,没有进行构造
}

编译错误:
error C2440: “return”: 无法从“DPoint3d”转换为“DPoint3d &&”
note: 无法将左值绑定到右值引用

 

改一下fun函数,直接返回一个对象,发现调用了DPoint3d(const DPoint3d&& pt);,外面的右值引用变量c也能正常使用,而且出了作用域之后,c立刻被释放了,析构函数被调用:

struct DPoint3d
{
    //! x coordinate
    double x;
    //! y coordinate
    double y;
    //! z coordinate
    double z;

    DPoint3d() = default;
    ~DPoint3d()
    {
        std::cout << "~DPoint3d" << endl;
    }
    DPoint3d(const DPoint3d& pt)
    {
        std::cout << "123" << endl;
        x = pt.x;
        y = pt.y;
        z = pt.z;
    }

    DPoint3d(const DPoint3d&& pt)
    {
        std::cout << "456" << endl;
        x = pt.x;
        y = pt.y;
        z = pt.z;
    }

    DPoint3d& operator=(DPoint3d&& pt) {
        std::cout << "789" << endl;
        x = pt.x;
        y = pt.y;
        z = pt.z;
    }
};

DPoint3d fun()
{
    DPoint3d a; // 默认构造
    a.x = 1;
    a.y = 2;
    a.z = 3;
    // return a; // 报错:无法将左值绑定到右值引用
    //return std::move(a); // 返回右值引用,没有进行构造
    return a; // 返回右值引用,没有进行构造
}


int main()
{
        DPoint3d&& c = fun();//DPoint3d c = fun();效果一样
        std::cout << c.x << endl;
        int i = 0;
        ++i;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值