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

标签 c++ c++11 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.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 构造函数。

为什么这里没有进行搬迁施工?我错过了什么吗?

谢谢。

最佳答案

It seems that in the line myObject c = GetObject_Complex(1,0), copy operation is happening.

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

Why move construction is not happening here?

没有 move 构造函数,因为编译器从函数调用结果中省略了 move 作为优化。

关于c++ - 即使在 RVO 禁用时定义了 move 构造函数,也会发生对象复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64778919/

相关文章:

c++ - 是否有可能在 C++ 中使用 std::atomic_flag 获得线程锁定机制?

linux - 在 for 循环中 move 文件

c++ - CUDA 和复制构造函数

c++ - 如果该结构的另一个成员已知,则修改 vector 中的结构成员

c++ - std::array 的大小是否由标准定义

c++ - 阻止所有模板化派生类型的通用模板函数

powershell - 将具有特定扩展名的文件 move 到更高层次的文件夹中

c++ - 指针是否有可能在没有任何数据拷贝的情况下由 vector 拥有?

c++ - 如何将十六进制字符串分配给 char[] 变量?

c++ - 有没有一种干净的方法可以在 leonardo 中禁用 USBCore 的 RX 控制?