使用移动语义:右值引用作为方法参数

Using move semantics: rvalue reference as a method parameter

提问人:DoehJohn 提问时间:6/3/2020 最后编辑:DoehJohn 更新时间:6/3/2020 访问量:54

问:

我想仔细检查一下我对移动语义的理解。我的推理中是否遗漏了什么:

#include <iostream>

using std::cout;

struct A
{
    A() {cout<<"Constructor\n";}
    ~A() {cout<<"Desctuctor\n";}
    A(const A&) {cout<<"Copy Constructor\n";}
    A(A&&) noexcept {cout<<"Move Constructor\n";}
    int x{1}; 
};

int f1(A a)
{
    cout<<"f1(A a)\n";
    return a.x;
}

int f2 (A&& a)
{
    cout<<"f2 (A&& a)\n";
    return a.x;
}

int main()
{
  A a1, a2;
  f1(std::move(a1));
  f2(std::move(a2));
}

输出:

Constructor
Constructor
Move Constructor
f1(A a)
Desctuctor
f2 (A&& a)
Desctuctor
Desctuctor

从我所看到的,我没有创建任何额外的副本,甚至是“轻量级”移动副本,这很酷。 所以我现在的理解是,如果我要使用移动语义,我最好总是编写函数/方法签名来接受 r 值,以避免任何不必要的副本。还是我错过了其他东西?f2()

C++ C++11 按引用传递 move-semantics rvalue-reference

评论

0赞 Taekahn 6/3/2020
你缺少一个按值获取其参数的人。添加然后再考虑结果。
0赞 xaxxon 6/3/2020
试图在不采用实际代码的情况下进行优化,使用优化的构建,并实际对其进行分析是愚蠢的差事。在构造函数和析构函数中有一个 print 语句这一事实从根本上改变了生成的二进制文件的构建方式,因为现在它们具有可观察的行为。你从根本上不了解如何优化代码,你走错了学习之路。
1赞 rekkalmd 6/3/2020
你的 和 不是过程函数(非 void),要么将它们定义为函数,要么用一个值,建议在你把一个作为数据类型返回的同时,也建议这样做,所以,你的代码首先是不安全的实现。f1()f2()voidreturnmain()int
0赞 M.M 6/3/2020
具有讽刺意味的是,您缺少一些#include

答:

2赞 xaxxon 6/3/2020 #1

你几乎总是最好只接受你要按值保留的输入(除了奇数类型,它们的移动成本非常高)。

它保持相同的性能级别(在常见方案中),并使代码非常易于理解。它还非常清楚地表明您的代码保留了该值(因为它可以保证被移出),因为右值引用不会强制执行该值。

如您所见,删除 print 语句时,示例的计时和生成的代码是相同的:http://quick-bench.com/ADU4fzd0ISk0UrLboVhC-Pd7RmI

评论

0赞 DoehJohn 6/3/2020
哇,尽管一个调用移动构造函数,而另一个非汇编程序代码是相同的,但这怎么可能?
0赞 xaxxon 6/3/2020
@DoehJohn它没有调用移动构造函数 - 这就是原因。en.cppreference.com/w/cpp/language/copy_elision verywellmind.com/....