简体   繁体   English

接受值或rvalue引用的仅移动参数

[英]Accept move-only parameter by value or rvalue reference

The accepted answer of this post Pass by value vs pass by rvalue reference says that: 这个帖子的接受答案通过价值与通过右值参考传递说明:

For move-only types (as std::unique_ptr ), pass-by-value seems to be the norm... 对于仅移动类型(如std::unique_ptr ),pass-by-value似乎是常态......

I'm a little bit doubtful about that. 我对此有点怀疑。 Let's say there is some non-copyable type, Foo , which is also not cheap to move; 让我们说有一些不可复制的类型, Foo ,它也不便宜移动; and some type Bar that has a member Foo . 和一些有成员Foo类型Bar

class Foo {
public:
    Foo(const Foo&) = delete;
    Foo(Foo&&) { /* quite some work */ }
    ...
};

class Bar {
public:
    Bar(Foo f) : f_(std::move(f)) {}    // (1)
    Bar(Foo&& f) : f_(std::move(f)) {}  // (2)
    // Assuming only one of (1) and (2) exists at a time

private:
    Foo f_;
};

Then for the following code: 然后为以下代码:

Foo f;
...
Bar bar(std::move(f));

Constructor (1) incurs 2 move constructions, while constructor (2) only incurs 1. I also remember reading in Scott Meyers's Effective Modern C++ about this but can't remember which item immediately. 构造函数(1)引发2个移动构造,而构造函数(2)只引发1.我还记得在Scott Meyers的Effective Modern C ++中读到这个但是不能立即记住哪个项目。

So my question is, for move-only types (or more generally, when we want to transfer the ownership of the argument), shouldn't we prefer pass-by-rvalue-reference for better performance? 所以我的问题是,对于仅移动类型(或者更一般地说,当我们想要转移参数的所有权时),我们是否应该更倾向于通过rvalue-reference来获得更好的性能?

UPDATE: I'm aware that the pass-by-value constructors/assignment operators (sometimes called unifying ctors/assignment operators) can help eliminate duplicate code. 更新:我知道pass-by-value构造函数/赋值运算符(有时称为统一 ctors /赋值运算符)可以帮助消除重复的代码。 I should say I'm more interested in the case when (1) performance is important, and (2) the type is non-copyable and so there are no duplicate ctors/assignment operators which accept const lvalue reference arguments. 我应该说我对以下情况更感兴趣:(1)性能很重要,(2)类型是不可复制的,因此没有重复的ctors /赋值运算符接受const左值引用参数。

UPDATE 2: So I've found Scott Meyers's blog about the specific problem: http://scottmeyers.blogspot.com/2014/07/should-move-only-types-ever-be-passed.html . 更新2:所以我找到了Scott Meyers关于具体问题的博客: http//scottmeyers.blogspot.com/2014/07/should-move-only-types-ever-be-passed.html This blog discusses the reason that he advocates in Item 41 of his Effective Modern C++ that: 这篇博客讨论了他在有效现代C ++第41项中提倡的原因:

Consider pass by value only for copyable parameters ...that are cheap to move ...[and] always copied . 考虑仅为可复制参数传递值... 移动便宜 ...... [和] 总是被复制

There is an extensive discussion in that item about pass by value vs. rvalue reference, too much to be quoted here. 在该项目中有关于按值传递与右值参考的广泛讨论,这里引用太多。 The point is, both ways have their own advantages and disadvantages, but for transferring the ownership of a move-only object, pass by rvalue reference seems to be preferable. 关键是,两种方式都有各自的优点和缺点,但是为了转移仅移动对象的所有权,通过右值引用似乎更可取。

In this case we can have our cake and eat it. 在这种情况下,我们可以吃蛋糕然后吃。 A template constructor enabled only for Foo-like references gives us perfect forwarding plus a single implementation of a constructor: 仅为类似Foo的引用启用的模板构造函数为我们提供了完美的转发以及构造函数的单个实现:

#include <iostream>
#include <utility>

class Foo {
public:
    Foo() {}
    Foo(const Foo&) = delete;
    Foo(Foo&&) { /* quite some work */ }
};

class Bar {
public:
  template<class T, std::enable_if_t<std::is_same<std::decay_t<T>, Foo>::value>* = nullptr>
    Bar(T&& f) : f_(std::forward<T>(f)) {}  // (2)
    // Assuming only one of (1) and (2) exists at a time

private:
    Foo f_;
};

int main()
{
  Foo f;
  Bar bar(std::move(f));

  // this won't compile
//  Foo f2;
//  Bar bar2(f2);

}

Background 背景

It's hard to imagine a class that's expensive to move: move semantics come exactly from the need to give a fast alternative to copies, when semantics allow. 很难想象一个移动成本昂贵的类:移动语义完全取决于语义允许时快速替换副本的需要。

You bring the example of std::string and SSO. 您带来了std::string和SSO的示例。 However that example is clearly flawed (I doubt they even turned on optimizations) because copying 16 bytes through memcpy should take a bunch of CPU cycles since it can be implemented in 1 SIMD instruction to store them all at once. 然而,这个例子显然存在缺陷(我怀疑他们甚至开启了优化),因为通过memcpy复制16个字节应该占用一堆CPU周期,因为它可以在1个SIMD指令中实现,以便一次性存储它们。 Also, MSVC 10 is really old. 此外,MSVC 10真的很老了。


So my question is, for move-only types (or more generally, when we want to transfer the ownership of the argument), shouldn't we prefer pass-by-rvalue-reference for better performance? 所以我的问题是,对于仅移动类型(或者更一般地说,当我们想要转移参数的所有权时),我们是否应该更倾向于通过rvalue-reference来获得更好的性能?

I shan't talk about performance, because it's such a peculiar aspect and can't be analyzed "in general". 我不会谈论性能,因为它是如此奇特的方面,不能“一般”分析。 We'd need concrete cases. 我们需要具体案例。 Also, compiler optimizations also needs to be considered; 此外,还需要考虑编译器优化; quite heavily, actually. 实际上相当重。 And not to forget a thorough performance analysis. 不要忘记彻底的性能分析。

std::unique_ptr is a bit different because (i) can only be moved due to owning semantics (ii) it is cheap to move. std::unique_ptr是有点不同的,因为(ⅰ)只能被移动,由于拥有语义(ii)其便宜的移动。

My view. 我的观点。 I would say if you have to provide a "faster" alternative as an API, provide both - just like std::vector::push_back . 我想说如果你必须提供一个“更快”的替代品作为API,提供两者 - 就像std::vector::push_back It could have, as you say, slight improvements. 正如你所说,它可能会有轻微的改进。
Otherwise, even for move-only types, passing by const-reference still works and if you think it wouldn't, go for pass-by-value. 否则,即使对于仅移动类型,通过const-reference传递仍然有效,如果你认为它不会,则转换为pass-by-value。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 返回仅移动右值引用 - returning a move-only rvalue reference 包含仅移动类型的类的构造函数是应该通过引用还是通过右值引用来接收仅移动类型? - Should a constructor for a class that contains a move-only type receive the move-only type by reference or by rvalue reference? C ++:传递std :: unique_ptr(move-only type)rvalue作为参数时复制elision - C++: Copy elision when passing std::unique_ptr (move-only type) rvalue as parameter 接受右值引用作为参数的方法的 Swig 行为 - Swig behavior for methods that accept rvalue reference as a parameter 在右值引用参数上使用 std::move 的原因 - Reason to use std::move on rvalue reference parameter 使用移动语义:右值引用作为方法参数 - Using move semantics: rvalue reference as a method parameter 如何使模板右值引用参数仅绑定到右值引用? - How to make template rvalue reference parameter ONLY bind to rvalue reference? 为什么除了在 Uref 实施例中对右值的引用之外,还允许 std::move 接受对右值的引用? - Why was it nessesury to allow std::move accept reference to rvalue besides reference to rvalue in Uref embodiment for both? 为什么移动返回一个rvalue引用参数需要用std :: move()包装它? - Why move return an rvalue reference parameter need to wrap it with std::move()? 让函数指针模板参数接受右值引用是否合法? - Is it legal to have a function pointer template parameter accept an rvalue reference?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM