即使在禁用RVO时定义了move构造函数,也会发生对象复制

问题描述

我碰巧发现了一种情况,我正在按值从函数中返回对象。

在return语句中使用条件语句,可以避免RVO

代码如下:

#include <iostream>
#include <cstring>

class myObject {
    public:
    myObject() {
        std::cout <<"Default Constructor called" << std::endl;
        buffer = new char[1000];
        this->sz = 1000;
    }
    myObject(std::size_t sz) {
        buffer = new char[sz];
        this->sz = sz;
    }
    myObject(const myObject& other) {
        std::cout <<"copy Constructor called" << std::endl;
        buffer = new char[other.sz];
        sz = other.sz;
        std::memcpy(buffer,other.buffer,other.sz);
    }

    myObject(myObject&& other) noexcept {
        std::cout <<"Move Constructor called" << std::endl;
        buffer = other.buffer;
        sz = other.sz;
        other.buffer = NULL;
        other.sz = 0;
    }
    myObject& operator=(myObject&& other) noexcept {
        std::cout <<"Move Assignment called" << std::endl;
        if(buffer != NULL) {
            delete[] buffer;
            sz = 0;
        }
        buffer = other.buffer;
        sz = other.sz;
        other.buffer = NULL;
        other.sz = 0;
        
        return *this;
    }
    
    myObject& operator=(const myObject& other) {
        // self ref ignored
        std::cout <<"copy Assignment called" << std::endl;
        if(buffer != NULL) {
            delete[] buffer;
            sz = 0;
        }
        buffer = new char[other.sz];
        sz = other.sz;
        std::memcpy(buffer,other.sz);
        return *this;
    }
    ~myObject() {
        std::cout <<"~myObject()" << std::endl;
        if(buffer != NULL) {
            delete[] buffer;
            buffer = NULL;
        }
    }
    char * buffer = NULL;
    std::size_t sz = 0;
};


myObject Getobject_Complex(int x,int y) {
    myObject obj;
    myObject d;
    return x > y ? obj : d; // intentionaly made conditional to avoid Return value optimization
}

int main() {

    myObject c = Getobject_Complex(1,0); // Why move constructor is not called here ?

    std::cout << std::endl << std::endl;

    myObject d = std::move(c);
    std::cout << std::endl << std::endl;

    myObject e;
    std::cout << std::endl << std::endl;
    e = std::move(d);

}

这里使用g++ -g -std=c++11 gcc version 7.5.0

输出
Default Constructor called
Default Constructor called
copy Constructor called
~myObject()
~myObject()


Move Constructor called


Default Constructor called


Move Assignment called
~myObject()
~myObject()
~myObject()

似乎在myObject c = Getobject_Complex(1,0)行中,正在发生复制操作。但是据我了解,当禁用RVO并使用move操作定义对象时,应该调用move构造函数

为什么这里没有进行搬迁施工?我想念什么吗?

谢谢。

解决方法

似乎在myObject c = GetObject_Complex(1,0)行中,正在执行复制操作。

排序但不完全。更准确地说,复制操作发生在GetObject_Complex 三元条件运算符的结果被复制到临时返回值。

为什么这里没有进行搬迁建设?

没有move构造函数,因为编译器从函数调用的结果中消除了对移动的优化。