通过ref-qualifier重载运算符以防止临时运行是否合理?

Mr.*_*nko 6 c++ ref-qualifier

我刚刚想到operator+&co可以this为rvalues 操作; 即给定一个类C,它可以这样做:

class C {
    // ...
    C operator-( const C& rhs ) const & {
        C result = *this;
        result -= rhs;
        return result;
    }
    C&& operator-( const C& rhs ) && {
        *this -= rhs;
        return std::move( *this );
    }
};
Run Code Online (Sandbox Code Playgroud)

这样可以通过简单地就地修改临时值来防止复制.

这会像我期望的那样表现吗?这是一个合理的优化还是编译器会创建同样快速的代码?

Bar*_*rry 5

假设我们只是换行std::string并做一个简化版本operator+:

struct C { 
    std::string val;

    C&& operator+(const C& rhs) && {
        val += rhs.val;
        return std::move(*this);
    }   

    std::string::iterator begin() { return val.begin(); }
    std::string::iterator end() { return val.end(); }
};
Run Code Online (Sandbox Code Playgroud)

有了这个,这很好:

for (char c : C{"hello"}) { .. }
Run Code Online (Sandbox Code Playgroud)

range-for表达式将延长临时的生命周期,所以我们没问题.但是,考虑一下:

for (char c : C{"hello"} + C{"goodbye"}) { .. }
Run Code Online (Sandbox Code Playgroud)

我们有效地:

auto&& __range = C{"hello"}.operator+(C{"goodbye"});
Run Code Online (Sandbox Code Playgroud)

在这里,我们没有将临时绑定到引用.我们绑定了一个参考.该对象不会延长其生命周期,因为......它不是一个对象.所以我们有一个悬空引用和未定义的行为.对于期望这种方式起作用的用户来说,这将是非常令人惊讶的:

for (char c : std::string{"hello"} + std::string{"goodbye"}) { .. }
Run Code Online (Sandbox Code Playgroud)

你必须返回一个值:

C operator+(const C& rhs) && {
    val += rhs.val;
    return std::move(*this);
}
Run Code Online (Sandbox Code Playgroud)

这解决了这个问题(现在我们有临时扩展),如果移动你的对象比复制它们便宜,这是一个胜利.