移动省略优化
Move elision optimization
考虑 class:
的两个实现
struct S1
{
std::vector< T > v;
void push(T && x) { v.push_back(std::move(x)); }
void push(T const & x) { push(T(x)); }
void pop() { v.pop_back(); }
void replace(T && x) { pop(); push(std::move(x)); }
void replace(T const & x) { replace(T(x)); }
};
struct S2
{
std::vector< T > v;
void push(T x) { v.push_back(std::move(x)); }
void pop() { v.pop_back(); }
void replace(T x) { pop(); push(std::move(x)); }
};
S1
的 push
重载正是我想要的。 S2
的 push
是一种更简洁的表达方式。
但我担心对象的过度移动构造会带来不利影响。
对于某些 t
,其中 decltype(t)
是 T&
,现代编译器能否将表达式 std::move(T(std::move(t)))
简化为 std::move(t)
?现代编译器可以优化掉不必要的动作吗?或者这是标准禁止的?
不,除了在 as-if 优化下,省略是不合法的。
现在,如果 foo()
是一个 return 是 T
的表达式,那么 S{}.push(foo())
可以从 return 的值中省略移动 foo()
进入push
的论证:只走一步。
但是如果我们S{}.push(std::move(foo())
,明确的std::move
阻止了省略的可能性。
通常更好的方法是基于放置的操作而不是基于推送的操作。
template<class...Args>
void emplace(Args&&...args) {
v.emplace_back( std::forward<Args>(args)... );
}
这让您可以将构造 T
的参数传递给对象,并使其直接在接收器(矢量)中构造,而不是移动或复制到其中。
可选:
template<class...Args,
decltype(T(std::declval<Args&&>()...))* =0
>
void emplace(Args&&...args) {
v.emplace_back( std::forward<Args>(args)... );
}
如果您需要 SFINAE 支持。评论说 "we expect a T
to be constructed here",如果不明显,也是礼貌的。
考虑 class:
的两个实现struct S1
{
std::vector< T > v;
void push(T && x) { v.push_back(std::move(x)); }
void push(T const & x) { push(T(x)); }
void pop() { v.pop_back(); }
void replace(T && x) { pop(); push(std::move(x)); }
void replace(T const & x) { replace(T(x)); }
};
struct S2
{
std::vector< T > v;
void push(T x) { v.push_back(std::move(x)); }
void pop() { v.pop_back(); }
void replace(T x) { pop(); push(std::move(x)); }
};
S1
的 push
重载正是我想要的。 S2
的 push
是一种更简洁的表达方式。
但我担心对象的过度移动构造会带来不利影响。
对于某些 t
,其中 decltype(t)
是 T&
,现代编译器能否将表达式 std::move(T(std::move(t)))
简化为 std::move(t)
?现代编译器可以优化掉不必要的动作吗?或者这是标准禁止的?
不,除了在 as-if 优化下,省略是不合法的。
现在,如果 foo()
是一个 return 是 T
的表达式,那么 S{}.push(foo())
可以从 return 的值中省略移动 foo()
进入push
的论证:只走一步。
但是如果我们S{}.push(std::move(foo())
,明确的std::move
阻止了省略的可能性。
通常更好的方法是基于放置的操作而不是基于推送的操作。
template<class...Args>
void emplace(Args&&...args) {
v.emplace_back( std::forward<Args>(args)... );
}
这让您可以将构造 T
的参数传递给对象,并使其直接在接收器(矢量)中构造,而不是移动或复制到其中。
可选:
template<class...Args,
decltype(T(std::declval<Args&&>()...))* =0
>
void emplace(Args&&...args) {
v.emplace_back( std::forward<Args>(args)... );
}
如果您需要 SFINAE 支持。评论说 "we expect a T
to be constructed here",如果不明显,也是礼貌的。