11

有人告诉我,在 C++03 中,临时变量是隐式不可修改的。

但是,以下在 GCC 4.3.4(在 C++03 模式下)上为我编译:

cout << static_cast<stringstream&>(stringstream() << 3).str();

这是如何编译的?

(我不是在谈论关于绑定到引用的临时规则。)

4

2 回答 2

20

有人告诉我,在 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。它们总是非常量

于 2011-06-24T10:02:35.847 回答
8

首先,“修改临时对象”和“通过右值修改对象”是有区别的。我会考虑后者,因为前者对于讨论 [1] 并没有多大用处。

我在3.10/103.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 提供代码!)

于 2011-06-24T10:07:07.337 回答