Notes on C++ Copy Elision
Omits copy and move (since C++11) constructors, resulting in zero-copy pass-by-value semantics.
以上是 copy elision 的解释。
下面列举一些代码:
1 | void get_F1(S& s) { |
和
1 | T get_object(args...) { |
至少一般我们被教育过,不要 return std::move(t)
, 同时我们知道,返回某个 S
类型的量,可能会有 Copy Elision 的优化,帮助我们就地在外部构造这个值 (constructing the automatic object directly into the exception object.
)
Value Category and Guaranteed Copy Elision
C++11 定义了 Value Categories. C++ 中,每个 expression 都有一个 value category
我们考虑仅定义 lvalue
和 rvalue
. 字面量 2
肯定是 rvalue
, 而 lvalue
被视作 localizable value
, 那么,简单句几个例子:
v
是一个std::vector
,v.front()
是一个 lvalue*p
是一个 lvalue- 甚至一个字符串字面量都是一个不可更改值的 lvalue.
而 nullptr
, 'a'
, 7
这些被视作 rvalue
.
lvalue
可以被转成 rvalue
,所以 y = x
是可以的,当然 7 = 8
就不行啦。
上面只是一个非常模糊的说明,C++11 定义了下面的内容:
而 Guaranteed copy elision through simplified value categories 定义了新的 value category, 随后又了如下变更:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0135r1.html
这意味着,如果你有一个
1 | T f() { |
这里需要根据 f()
的上下文推断,T()
是个 prvalue, 那么 C++ 17 会强制 1 仅调用一次 T 的构造函数
然后,再看 2:
If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object. [ Example**:
T x = T(T(T()));
calls theT
default constructor to initializex
. ]**
所以这里构造函数也只会走一次。
以上内容在 C++17 之后是强制的。
NRVO
我们再考虑 NRVO:
1 | T get_object(args...) { |
我们贴两个图:
这里描述了 NRVO 和 NRVO 失败的情况。可以看到,对于一个 HardToCopyAndEasyToMove
的结构,即使不 return std::move(..)
, 编译器也能正确的优化
遇上 scoped_guard
如果你想在参数返回之前,做一些检查,在 go
里面,你没准这么写了:
1 | var s Status // when init s.ok() == true |
不谈代码好不好,这里逻辑上是可以的,因为 Go 万物都是 Copy。
当你想在 C++ 里面实现这些东西的时候,比如:
1 | Status s; // when moved, it will be ok |
如果这里走了 move, 那我们有 evaluation order: https://en.cppreference.com/w/cpp/language/eval_order
我们可以看到,这里可能先发生 move, 再来 check s, move 之后 s 可能就不能满足用户的预期了。
感想
其实我也不懂 C++,有什么地方写错了,请立刻通知我,我会第一时间查证和改正。
查阅的时候,虽然感觉 C++ 规则很复杂,但是大部分时候,即使不熟悉这些细节,正常写代码也能保证高效率。正如没有受过法律的正常人,也很少会犯法。
好了,搞完了,接着打逆转裁判了。
References
- value category
- copy elision
- Guaranteed copy elision through simplified value categories http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html
- C++ Templates 2nd