一点点复制移动

struct Test {
    Test() = default;
    Test(const Test&) {
        std::cout << "copy ctor" << std::endl;
    }
    Test(Test&&) {
        std::cout << "move ctor" << std::endl;
    }
};

Test test(Test t) {
    return t;
}

int main() {
    Test t1;
    auto t2 = test(t1);
    return 0;
}

也算是日经问题了, 但我太弱了, 还是得记一下, 首先我们看上面的代码, 输出是

copy ctor
move ctor

第一个 copy ctor 很好理解, 那么第二个是哪里的呢? 答案是 test 返回的时候, 首先因为 t 是形参, 所以在 return 这里不满足 copy elision 的要求, 所以这里不会进行优化, 故需要调用一次构造函数, 比如我们把 auto t2 = test(t1) 修改为 test(t1), 会发现输出没有改变

那为什么 return t 的时候调用的是移动构造函数而不是复制构造呢, 参见class.copy.elision #3, 简单点说就是在需要复制语义时, 如果条件允许, 可以使用移动操作, 那么我们把移动构造删掉应该可以使用复制构造了吧, 那就改成下边这样

struct Test {
    Test() = default;
    Test(const Test&) {
        std::cout << "copy ctor" << std::endl;
    }
    Test(Test&&) = delete;
};

Test test(Test t) {
    return t;
}

int main() {
    Test t1;
    auto t2 = test(t1);
    return 0;
}

这段代码用 C++17 是可以编译的, 并且打印结果和预期一样, 是两个 copy ctor, 但是在 C++17 之前(以及 C++11 之后)编译是通不过的, 这又是为什么呢?

答案是在复制初始化的时候, 如果初始化器是一个右值, 重载决议的时候会选择移动构造, 而如果移动构造被显式弃置(delete)了, 就会报错, 但是在 C++17 之后, 因为 copy elision 是强制的, 所以这里不需要调用移动构造, 从而也就不会报错, 比如我们还是把 auto t2 = test(t1) 改成 test(t1), 在 C++17 之前也可以通过编译了

但是除此之外还有一个问题, 当我们把显式弃置移动构造的语句删掉时, 变成下边这样

struct Test {
    Test() = default;
    Test(const Test&) {
        std::cout << "copy ctor" << std::endl;
    }
};

Test test(Test t) {
    return t;
}

int main() {
    Test t1;
    auto t2 = test(t1);
    return 0;
}

还是可以正常通过编译的, 尽管当用户声明了复制构造函数之后, 移动构造函数不会被隐式声明, 但是重载决议会忽略掉这件事, 因为会阻止从右值复制初始化, 参见移动构造函数一节中所述:

The deleted implicitly-declared move constructor is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue).

原文链接: https://www.cnblogs.com/Mu001999/p/12542263.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    一点点复制移动

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/336711

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月1日 下午10:46
下一篇 2023年3月1日 下午10:47

相关推荐