将此指针按值分配给 getter 的 return 值是什么意思?
What is the meaning of assigning to return value of getter taking this pointer by value?
当我跳到现有代码并错误地使用 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;
不同,因此前者编译而后者不编译(除了类型 A
和 int
)?
- 将
void operator=(A const& other) { x = other.x; }
更改为void operator=(A const& other) & { x = other.x; }
会使b.getAbyVal() = A{7};
编译失败。为什么会这样?
what in b.getAbyVal() = A{7};
is different from b.getXbyVal() = 3;
so that the former compiles and the latter doesn't (beside the fact that the types are A
and int
)?
区别恰恰是一个函数returns一个class类型,另一个函数returns一个POD类型。临时 int
,例如不能分配给:
42 = x; // error
类似地,该语言也不允许分配给从函数返回的临时 int
。这不是 user-defined class 类型的默认行为,因此分配给临时 A
编译:
A{} = x; // ok
changing void operator=(A const& other) { x = other.x; }
to void operator=(A const& other) & { x = other.x; }
makes b.getAbyVal() = A{7};
fail to compile. Why is this the case?
在末尾添加一个&
称为ref-qualifier,并允许user-definedclass在出现时具有与POD类型相同的语义分配给一个临时的。在 operator=
末尾添加 &
将其限制为仅用于 l-value (基本上,命名变量或从函数返回的引用)。
A{} = x; // now error
A a;
a = x; // still ok
what in b.getAbyVal() = A{7}; is different from b.getXbyVal() = 3; so
that the former compiles and the latter doesn't (beside the fact that
the types are A and int)?
令人惊讶的是,类型的差异正是导致一个编译正确而另一个编译失败的原因。
A
为其定义了一个赋值运算符,因此编译器尽职尽责地在 return 值上调用它(只是为了稍后丢弃整个对象)。但是您编写的代码支持这一点。从编译器的角度来看,尽管对象将被根除(副作用 在正式的说法中),您的赋值运算符中可能还发生了一些其他有趣的事情。
将 int
作为 return 值,编译器 知道 将值赋给 int 没有副作用,因此将任何值赋给对象立即根除没有任何意义。
当我跳到现有代码并错误地使用 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;
不同,因此前者编译而后者不编译(除了类型A
和int
)?- 将
void operator=(A const& other) { x = other.x; }
更改为void operator=(A const& other) & { x = other.x; }
会使b.getAbyVal() = A{7};
编译失败。为什么会这样?
what in
b.getAbyVal() = A{7};
is different fromb.getXbyVal() = 3;
so that the former compiles and the latter doesn't (beside the fact that the types areA
andint
)?
区别恰恰是一个函数returns一个class类型,另一个函数returns一个POD类型。临时 int
,例如不能分配给:
42 = x; // error
类似地,该语言也不允许分配给从函数返回的临时 int
。这不是 user-defined class 类型的默认行为,因此分配给临时 A
编译:
A{} = x; // ok
changing
void operator=(A const& other) { x = other.x; }
tovoid operator=(A const& other) & { x = other.x; }
makesb.getAbyVal() = A{7};
fail to compile. Why is this the case?
在末尾添加一个&
称为ref-qualifier,并允许user-definedclass在出现时具有与POD类型相同的语义分配给一个临时的。在 operator=
末尾添加 &
将其限制为仅用于 l-value (基本上,命名变量或从函数返回的引用)。
A{} = x; // now error
A a;
a = x; // still ok
what in b.getAbyVal() = A{7}; is different from b.getXbyVal() = 3; so that the former compiles and the latter doesn't (beside the fact that the types are A and int)?
令人惊讶的是,类型的差异正是导致一个编译正确而另一个编译失败的原因。
A
为其定义了一个赋值运算符,因此编译器尽职尽责地在 return 值上调用它(只是为了稍后丢弃整个对象)。但是您编写的代码支持这一点。从编译器的角度来看,尽管对象将被根除(副作用 在正式的说法中),您的赋值运算符中可能还发生了一些其他有趣的事情。
将 int
作为 return 值,编译器 知道 将值赋给 int 没有副作用,因此将任何值赋给对象立即根除没有任何意义。