Если временные данные неявно не модифицируются, как это работает?
Мне говорят, что в 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()
не действует дляconst
show()
[тьфу, почему?!] было ложным.
Таким образом, ответ (слегка изменяя формулировку вопроса для заключения) заключается в том, что значения 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{});
}
(Спасибо Люку Дантону за код!)