可以采取哪些措施来防止对返回值进行误导性分配?

alf*_*lfC 4 c++ rvalue user-defined-types assignment-operator

使用 C++ 多年后,我意识到使用自定义类时语法中的一个怪癖。尽管是正确的语言行为,但它允许创建非常具有误导性的界面。

这里的例子:

class complex_arg {
    double r_;
    double phi_;
 public:
    std::complex<double> value() const {return r_*exp(phi_*std::complex<double>{0, 1});}
};

int main() {
    complex_arg ca;
    ca.value() = std::complex<double>(1000., 0.);  // accepted by the compiler !?
    assert( ca.value() != std::complex<double>(1000., 0.) ); // what !?
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/Y5Pcjsc8d

可以对类定义做什么来防止这种行为? (或者至少标记类的用户第三行并没有真正执行任何分配。)

我只看到一种出路,但它需要修改类,并且它不能很好地扩展(对于可以移动的大型类)。

    const std::complex<double> value() const;
Run Code Online (Sandbox Code Playgroud)

我也尝试过[[nodiscard]] value(),但没有帮助。

作为最后的手段,也许可以对返回的类型做一些事情std::complex<double>(也就是说,假设一个人控制着该班级)


请注意,我知道有时可能需要(优化)分配给新获得的值并将其传递给另一个函数f( ca.value() = bla )。我并不是质疑这种用法本身(尽管它也很令人困惑);我的问题主要是ca.value() = bla;作为一个独立的声明,它并不像它看起来的那样。

use*_*570 5

通常,我们可以调用对象的成员函数,无论该对象的值类别是左值还是右值。

可以对类定义做什么来防止这种行为?

在现代 C++ 之前,没有办法阻止这种用法。但从 C++11 开始,我们可以引用限定成员函数来执行您要求的操作,如下所示。

成员函数

在重载决策期间,具有类的 cv 限定符序列的非静态成员函数X将按如下方式处理

  • 无引用限定符:隐式对象参数具有对 cv 限定的左值引用类型X,并且还允许绑定右值隐式对象参数

  • 左值引用限定符:隐式对象参数具有对 cv 限定的左值引用类型X

  • 右值引用限定符:隐式对象参数具有对 cv 限定的 X 的右值引用类型


这使我们能够满足您对自定义托管类的要求。特别是,我们可以&限定复制赋值运算符。

struct C
{
    C(int)
    {
      std::cout<<"converting ctor called"<<std::endl;
    }
    C(){
        std::cout<<"default ctor called"<<std::endl;
    }
    C(const C&)
    {
     std::cout<<"copy ctor called"<<std::endl;
    }
//-------------------------v------>added this ref-qualifier
    C& operator=(const C&) &
    {
    std::cout<<"copy assignment operator called"<<std::endl;;
    return *this;
    }

};
C func()
{
    C temp;
    return temp;
}

int main()
{
//---------v---------> won't work because assignment operator is & qualified
    func() = 4;
}
Run Code Online (Sandbox Code Playgroud)