Если временные данные неявно не модифицируются, как это работает?

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

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

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

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

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

2 ответа

Решение

Мне говорят, что в 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. Они всегда неконстантны.

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

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

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

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

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

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

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


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

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

Другие вопросы по тегам