C++ 如何对操作员返回值强制执行RVO?
如何在最后3家运营商中实施RVO:C++ 如何对操作员返回值强制执行RVO?,c++,rvo,nrvo,C++,Rvo,Nrvo,如何在最后3家运营商中实施RVO: Noisy(int) Noisy(int) Noisy(int) Noisy(int) Noisy(int) Noisy(int) Noisy(int) +(const Noisy&)& Noisy(int) +(const Noisy&) && Noisy(Noisy&&) +(const Noisy&) && Noisy(Noisy&&) +(const No
Noisy(int)
Noisy(int)
Noisy(int)
Noisy(int)
Noisy(int)
Noisy(int)
Noisy(int)
+(const Noisy&)&
Noisy(int)
+(const Noisy&) &&
Noisy(Noisy&&)
+(const Noisy&) &&
Noisy(Noisy&&)
+(const Noisy&) &&
Noisy(Noisy&&)
+(const Noisy&) &&
Noisy(Noisy&&)
+(const Noisy&) &&
Noisy(Noisy&&)
#包括
课堂噪音{
私人:
int m_值;
公众:
噪声(int值=0):m_值(值)
{
std::cout简短回答
使您的右值引用调用者+常量引用参数运算符返回一个右值引用,该右值引用是std::move
ed of*this
Noisy&& operator+(const Noisy& rhs) &&
{
std::cout << "+(const Noisy&)&&\n";
m_value += rhs.m_value;
return std::move(*this);
}
输出
noised()
嘈杂的
嘈杂的
嘈杂的
嘈杂的
嘈杂的
嘈杂的
========================
+(常数噪声&)&
嘈杂的
+(常数噪声&)&&
+(常数噪声&)&&
+(常数噪声&)&&
+(常数噪声&)&&
+(常数噪声&)&&
嘈杂(嘈杂&)
~noise():-1
========================
~noise():0
~noise():0
~noise():0
~noise():0
~noise():0
~noise():0
~noise():0
~noise():0
请注意,在初始构造a.operator+(b)
之后,结果对象通过右值引用沿着链向下传播。最后一个操作是将构造移动到z
(因此析构函数报告中的-1
)
我准备了一份关于你的运营商链接如何实现这项工作的详细描述,我将在下面发布,但最终它变得相当混乱。我只想说:
Noisy z = a.operator+(b).operator+(c).operator+(....
就是您正在做的,您需要获取链中所有超过(b)
的对象的lhs操作数,以将其右值引用推送到下一个调用。我显示的运算符将允许这样做
祝你好运,我希望我理解了你的目标。你的最后3个运算符返回了一个副本。你不能在这里执行RVO,因为这会修改这个
。@user207421运算符+
应该返回一个新值。但是它不应该修改操作数。因此它是错误的,但原因不同。@juanchopanza为什么它应该在有一个可以修改并返回的右值引用?@AndreyGodyaev这些是二进制运算符+
的预期语义。传递两个东西,就会得到另一个东西。修改任何一个操作数都会让人困惑。is嘈杂吗&&x=noise(1)+noise(1)
operator的版本是否安全?我认为这是一个悬而未决的参考。@AndreyGodyaev我刚才看到了你问题中的表达式。我以为你是在问我发布的示例。由于两个不同的operator+
implementation中存在歧义,你给出的代码行甚至无法与我示例中的运算符一起编译n(提供的一个,和嘈杂的操作员+(嘈杂的和右侧)
)。你是在问右值引用生存期扩展是否可以与该运算符一起使用吗?我认为不会,因此,如果这很关键,这是行不通的。因此,如果我想要安全的通用代码,我就必须使用返回<代码>嘈杂代码>的运算符。我仍然有一个问题:是什么阻止编译器删除冗余复制dur优化是什么?@AndreyGodyaev:事实上,你在副本构造函数中放入了一堆打印语句。副本不是“多余的”;它们是标准所要求的。编译器只有在确定代码的可见行为将保持不变的情况下才能删除它们。如果您=default
这些构造函数和运算符,那么编译器可以在它认为合适的地方删除它们。@Nicolas我看到了在有std::cout.Th和没有std::cout.Th的程序集中发生的情况e编译器很聪明。
Noisy&& operator+(const Noisy& rhs) &&
{
std::cout << "+(const Noisy&)&&\n";
m_value += rhs.m_value;
return std::move(*this);
}
#include <iostream>
class Noisy {
private:
int m_value;
public:
Noisy(int value = 0) : m_value(value)
{
std::cout << "Noisy()\n";
}
Noisy(const Noisy& other) : m_value(other.m_value)
{
std::cout << "Noisy(const Noisy&)\n";
}
Noisy(Noisy&& other) : m_value(other.m_value)
{
std::cout << "Noisy(Noisy&&)\n";
other.m_value = -1;
}
~Noisy()
{
std::cout << "~Noisy() : " << m_value << '\n';
}
Noisy operator+(const Noisy& rhs) const &
{
std::cout << "+(const Noisy&)&\n";
return Noisy(m_value + rhs.m_value);
}
Noisy&& operator+(const Noisy& rhs) &&
{
std::cout << "+(const Noisy&)&&\n";
m_value += rhs.m_value;
return std::move(*this);
}
Noisy operator+(Noisy&& rhs) const
{
std::cout << "+(Noisy&&)\n";
rhs.m_value += m_value;
return std::move(rhs);
}
};
int main()
{
Noisy a, b, c, d, e, f, g;
std::cout << "========================\n";
Noisy z = a + b + c + d + e + f + g;
std::cout << "========================\n";
return 0;
}
Noisy z = a.operator+(b).operator+(c).operator+(....