C++ 保证省略和链式函数调用
假设我有以下类型:C++ 保证省略和链式函数调用,c++,c++17,copy-elision,C++,C++17,Copy Elision,假设我有以下类型: struct X { X& operator+=(X const&); friend X operator+(X lhs, X const& rhs) { lhs += rhs; return lhs; } }; 我有一个声明(假设所有命名变量都是X类型的左值): 在C++17中,对于这个表达式将执行多少拷贝和移动,我有什么保证?那么非保证省略呢?好的,让我们从以下内容开始: X operato
struct X {
X& operator+=(X const&);
friend X operator+(X lhs, X const& rhs) {
lhs += rhs;
return lhs;
}
};
我有一个声明(假设所有命名变量都是X
类型的左值):
在C++17中,对于这个表达式将执行多少拷贝和移动,我有什么保证?那么非保证省略呢?好的,让我们从以下内容开始:
X operator+(X lhs, X const& rhs) {
lhs += rhs;
return lhs;
}
这将始终引发从参数到返回值对象的复制/移动。C++17并没有改变这一点,任何形式的省略都无法避免这种复制
现在,让我们看一下表达式的一部分:a+b
。由于operator+
的第一个参数是按值获取的,因此必须将a
复制到其中。这是一份。返回值将被复制到返回值中。这就是一个拷贝和一个移动/拷贝
现在,下一部分:(a+b)+c
C++17表示从a+b
返回的PR值将用于直接初始化运算符+
的参数。这不需要复制/移动。但此参数的返回值将从该参数复制。这就是1个拷贝和2个移动/拷贝
对最后一个表达式重复此操作,即1个副本和3个移动/副本sum
将从prvalue表达式初始化,因此不需要在那里进行复制
您的问题似乎是,在C++17中,参数是否仍然被排除在省略之外。因为。这不会改变;从省略中排除参数的原因尚未失效
“保证省略”仅适用于PRV值。如果它有名称,则不能是prvalue。这将执行1个复制构造和3个移动构造
a
以绑定到lhs
lhs
移出第一个+
+
的返回将通过省略绑定到第二个+
的by值lhs
参数lhs
的返回将导致第二个移动构造lhs
的返回将产生第三个移动构造+
返回的临时值将在sum
处构造-fno elide构造函数,否则您将有1个副本和3个移动
如果在此表达式之后未引用a
,则可以进一步优化:
X sum = std::move(a) + b + c + d;
导致0次拷贝和4次移动(使用-fno-elide构造函数执行7次移动)
上述结果已由X
确认,该X已检测复制和移动构造函数
更新
如果您对优化此功能的不同方法感兴趣,可以从重载X const&
和X&&
上的lhs开始:
friend X operator+(X&& lhs, X const& rhs) {
lhs += rhs;
return std::move(lhs);
}
friend X operator+(X const& lhs, X const& rhs) {
auto temp = lhs;
temp += rhs;
return temp;
}
这使事情下降到1副本和2移动。如果您愿意限制您的客户通过引用捕获您的+
返回,那么您可以从如下重载之一返回X&&
:
friend X&& operator+(X&& lhs, X const& rhs) {
lhs += rhs;
return std::move(lhs);
}
friend X operator+(X const& lhs, X const& rhs) {
auto temp = lhs;
temp += rhs;
return temp;
}
让你一个拷贝一个移动。请注意,在最新设计中,如果您的客户曾经这样做:
X&& x = a + b + c;
然后x
是一个悬空引用(这就是为什么std::string
不这样做的原因).其中一些将是移动-你的意思是1次复制和3次移动?以不同的方式表达Nicol对参数复制的评论:按值获取参数只会有助于删除复制,并且只有在使用参数时才有意义,即,std::move()
将其放在其他地方,例如:xrc(std::move(lhs));rc+=rhs;返回rc
@Barry:是的,我忘了从返回局部变量开始的移动是自动的。我想如果这整件事可以编译成相当于X sum(a);总和+=b;总和+=c;总和+=d代码>猜测这仍然很难。所以没有省略链?e、 g.将a+b
的返回直接构造成operator+(?,c)
?我甚至认为省略lhs的返回是不合法的。然而,我也不认为任何编译器的作者有任何动机使它合法化(无论如何没有人试图这样做)。为什么它可能是非法的?它将来会合法吗?@Orient:我想说的是标准不允许这样做。据我所知,从来没有人提出过。我怀疑原因是没有人知道如何实现它。但这些都是猜测,我不是编译专家。
X&& x = a + b + c;