Если временные данные неявно не модифицируются, как это работает? - PullRequest
11 голосов
/ 24 июня 2011

Я сказал , что в C ++ 03 временные значения неявно неизменяемы.

Однако для меня на GCC 4.3.4 (в режиме C ++ 03) компилируется следующее :

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

Как это компилируется?

не говорю о правилах, касающихся временных привязок к ссылкам.)

Ответы [ 2 ]

20 голосов
/ 24 июня 2011

Мне сказали, что в C ++ 03 временные значения неявно не модифицируются.

Это не правильно.Временные значения создаются, среди прочего, путем оценки значений r, и существуют как неконстантные значения, так и постоянные значения.Категория значения выражения и константность объекта, который оно обозначает, большей частью ортогональны 1 .Обратите внимание:

      std::string foo();
const std::string bar();

Учитывая приведенные выше объявления функций, выражение foo() является неконстантным значением, вычисление которого создает неконстантное временное значение, а bar() является постоянным значением, которое создает постоянное временное значение.

Обратите внимание, что вы можете вызвать любую функцию-член для неконстантного значения, что позволит вам изменить объект:

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";

Это должно быть достаточным доказательством, чтобы убедить вас, что временные значения не неявно постоянны.

1: Исключением являются скалярные значения, такие как 42. Они всегда неконстантны .

8 голосов
/ 24 июня 2011

Во-первых, есть разница между «модификацией временного объекта» и «модификацией объекта через значение». Я рассмотрю последнее, так как первое не очень полезно обсуждать [1].

Я нашел следующее в 3.10/10 (3.10/5 в C ++ 11):

Необходимо lvalue для объекта для того, чтобы изменить объект, кроме что значение класса также может использоваться для изменения своего референта под определенные обстоятельства. [Пример: функция-член, вызываемая для объекта (9.3) может изменить объект. ]

Итак, значения не являются const per se, но они являются неизменяемыми при любых, кроме некоторых определенных обстоятельствах.

Однако то, что вызов функции-члена может изменить значение r, может показаться мне указанием на то, что подавляющее большинство случаев для модификации объекта через значение r удовлетворяются .

В частности, утверждение (в исходном вопросе, с которым я связан), что (obj1+obj2).show() недопустимо для не const show() [тьфу, почему ?!] было ложным.

Таким образом, ответ (слегка изменяя формулировку вопроса для заключения), что значения , к которым осуществляется доступ через функции-члены , не по своей сути неизменяемы.


[1] - Примечательно, что если вы можете получить lvalue для временного значения из исходного rvalue, вы можете сделать с ним как угодно :

#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{});
}

(Спасибо Люку Дантону за код!)

...