有人告诉我,在 C++03 中,临时变量是隐式不可修改的。
但是,以下在 GCC 4.3.4(在 C++03 模式下)上为我编译:
cout << static_cast<stringstream&>(stringstream() << 3).str();
这是如何编译的?
(我不是在谈论关于绑定到引用的临时规则。)
有人告诉我,在 C++03 中,临时变量是隐式不可修改的。
但是,以下在 GCC 4.3.4(在 C++03 模式下)上为我编译:
cout << static_cast<stringstream&>(stringstream() << 3).str();
这是如何编译的?
(我不是在谈论关于绑定到引用的临时规则。)
有人告诉我,在 C++03 中,临时变量是隐式不可修改的。
这是不正确的。在其他情况下,临时变量是通过评估右值来创建的,并且有非 const 右值和 const 右值。表达式的值类别和它所表示的对象的常量性大多是正交的1。观察:
std::string foo();
const std::string bar();
鉴于上述函数声明,表达式foo()
是一个非 const 右值,其评估创建一个非 const 临时值,并且bar()
是一个创建 const 临时值的 const 右值。
请注意,您可以在非常量右值上调用任何成员函数,从而允许您修改对象:
foo().append(" was created by foo") // okay, modifying a non-const temporary
bar().append(" was created by bar") // error, modifying a const temporary
由于operator=
是成员函数,您甚至可以分配给非常量右值:
std::string("hello") = "world";
这应该足以让你相信临时变量不是隐含的 const。
1:一个例外是标量右值,例如 42。它们总是非常量。
首先,“修改临时对象”和“通过右值修改对象”是有区别的。我会考虑后者,因为前者对于讨论 [1] 并没有多大用处。
我在3.10/10
(3.10/5
在 C++11 中)发现了以下内容:
对象的左值是修改对象所必需的,但在某些情况下也可以使用类类型的右值来修改其所指对象。[示例:为对象(9.3)调用的成员函数可以修改该对象。]
因此,右const
值本身不是,但除了某些特定情况外,它们在所有情况下都是不可修改的。
但是,成员函数调用可以修改右值似乎向我表明,绝大多数通过右值修改对象的情况都得到满足。
特别是,对于非[ugh, why ?!](obj1+obj2).show()
无效的断言(在我链接到的原始问题中)是错误的。const
show()
因此,答案是(稍微改变结论的问题措辞)通过成员函数访问的右值本身并不是不可修改的。
[1] - 值得注意的是,如果您可以从原始右值获得临时的左值,您可以对它做任何您喜欢的事情:
#include <cstring>
struct standard_layout {
standard_layout();
int i;
};
standard_layout* global;
standard_layout::standard_layout()
{
global = this;
}
void modifying_an_object_through_lvalue(standard_layout&&)
{
// Modifying through an *lvalue* here!
std::memset(global, 0, sizeof(standard_layout));
}
int main()
{
// we pass a temporary, but we only modify it through
// an lvalue, which is fine
modifying_an_object_through_lvalue(standard_layout{});
}
(感谢 Luc Danton 提供代码!)