提问者:小点点

将此指针按值赋值给getter的返回值有什么意义?


当我跳转到一个现有代码并错误地使用getter来设置属性时,

obj.getProp() = otherProp;

而不是调用setter,

obj.setProp(otherProp);

我没有意识到错误,因为在编译或运行时没有错误; 这一任务导致了一次无操作。

所以我想到了下面这个示例,它输出337:

#include <iostream>

struct A {
    int x = 0;
    A(int x) : x(x) {}
    A(A& a) : x(a.x) {}
    void operator=(A const& other) { x = other.x; }
};

struct B {
    A a{3};
    int x{3};
    A  getAbyVal() { return a; }
    A& getAbyRef() { return a; }
    int getXbyVal() { return x; }
};

int main() {
    B b;
    std::cout << b.a.x;   // this and the other two cout print what I expect, but...
    b.getAbyVal() = A{7}; // ... I expected this to fail at compilation time in the first place...
    //b.getXbyVal() = 3;  // ... just like this fails.
    std::cout << b.a.x;
    b.getAbyRef() = A{7};
    std::cout << b.a.x;

}

所以我的问题有两重:

  • b.getAbyVal()=A{7};中的内容与b.getXByVal()=3;不同,因此前者可以编译,而后者不可以编译(除了类型是Aint)?
  • void operator=(A const&other){x=other.x;}更改为void operator=(A const&other)& {x=other.x;}使b.GetabyVal()=A{7};无法编译。 为什么会出现这种情况?

共2个答案

匿名用户

在B.getabyval()=A{7}中是什么; 与b.getXByVal()=3不同; 以便前者编译而后者不编译(除了类型是A和int之外)?

令人惊讶的是,类型的差异正是使一个编译正确,而另一个编译失败的原因。

a有一个为它定义的赋值运算符,因此编译器会在返回值上尽职地调用它(只是后来丢弃了整个对象)。 但您编写的代码支持这一点。 从编译器视图来看,在赋值运算符中可能发生了一些其他有趣的事情,尽管对象将被根除(正式的说法是副作用)。

使用int作为返回值,编译器知道将值赋给int没有副作用,因此将任何值赋给要立即根除的对象是没有任何意义的。

匿名用户

b.getAbyVal()=A{7};中的什么不同于b.getXByVal()=3;,因此前者可以编译,而后者不可以编译(除了类型是Aint)?

区别恰恰在于,一个函数返回类类型,而另一个函数返回POD类型。 例如,临时int不能分配给:

42 = x; // error

因此,类似地,该语言也不允许赋值给从函数返回的临时int。 这不是用户定义类类型的默认行为,因此将其分配给临时a将编译:

A{} = x; // ok

void operator=(A const&other){x=other.x;}更改为void operator=(A const&other)& {x=other.x;}使b.GetabyVal()=A{7};无法编译。 为什么会出现这种情况呢?

在末尾添加&称为ref-qualifier,它允许用户定义的类具有与POD类型相同的语义。 在operator=末尾添加一个&将限制它只能用于L值(基本上是命名变量或从函数返回的引用)。

A{} = x;  // now error
A a;
a = x;    // still ok