考虑以下代码:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
没有编译器会对此抱怨,甚至包括Clang。为什么 q() = ...
这一行是正确的?
注:该段内容已经是中文,无需翻译。
考虑以下代码:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
没有编译器会对此抱怨,甚至包括Clang。为什么 q() = ...
这一行是正确的?
如果一个函数的返回值是引用,那么它就是一个l-value(C++03)(5.2.2 [expr.call] / 10)
如果返回类型是基本类型,则会导致编译错误。(5.17 [expr.ass] / 1)
这种情况之所以能够起作用是因为你可以在类类型的r-values上调用成员函数(即使是非const
成员函数),而将foo
赋值给它是一个实现定义的成员函数:foo& foo::operator=(const foo&)
。条款5中的运算符限制仅适用于内置运算符(5 [expr] / 3),如果重载分辨率选择了运算符的重载函数调用,则应使用该函数调用的限制。
这就是为什么有时候建议返回类类型的对象作为const
对象(例如const foo q();
),但这可能会对C++0x产生负面影响,因为它可能会阻碍移动语义的正常工作。
std::cout << "Hello, world" << std::endl
。第一个 operator<<()
返回一个左值,你可以在它上面调用第二个 operator<<()
。因此,在返回值上调用方法的这种做法比许多人想象的更为普遍。 - MSalterscout
的情况下,它实际上返回一个左值(它返回自身和引用 *this
),而不是一个按值传递的东西。所以稍有不同。 - Seth Carnegiestd::cout << "duh" << std::endl
中,所有的operator<<
都返回非const引用(即左值),因为这些操作符都要求它们的第一个参数是非const引用,所以原始的std::ostream
对象不能是右值。在其他例子中(我认为这是问题的动机),临时对象上调用了非const函数。 - James Kanzeq()
返回struct foo
的副本,所以它将返回的结构体赋给了提供的值。struct foo
{
int a;
};
foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }
int main()
{
foo i;
i.a = 5;
//sets the contents of the newly created foo
//to the contents of your i variable
(*(q())) = i;
}
int blah() { int f = 4; return f; } int main() { int a = 99; blah() = a; }
这段代码有什么区别吗?是结构体的神奇之处吗?因为这段代码无法编译。 - Seth Carnegieint::operator=(int)
。这就是结构体的“神奇”之处:它们有默认方法。 - MSalterss/nothing/anything/
- Lightness Races in Orbit这个技术的一个有趣应用:
void f(const std::string& x);
std::string g() { return "<tag>"; }
...
f(g() += "</tag>");
g() +=
修改了临时变量,这可能比使用+
创建额外的临时变量更快,因为分配给g()返回值的堆已经有足够的空余容量来容纳</tag>
。
q()
返回一个结构体,然后您给它赋了一个值。这有什么问题吗? 问题在于q()
函数返回的是结构体类型的值,而结构体是值类型。这意味着当您将其赋值给另一个变量时,将创建结构体的一个副本,而不是引用原来的结构体。因此,在对副本进行更改时,原始结构体不会受到影响。 - Andy Johnson