Как вы можете изменить объект без вызова функций-членов?
В 3.10/10 в стандарте говорится:
Для изменения объекта требуется lvalue для объекта, за исключением того, что rvalue типа класса также может использоваться для изменения его референта при определенных обстоятельствах. [Пример: функция-член, вызываемая для объекта (9.3), может изменять объект. ]
Таким образом, значения r не изменяются, за исключением определенных условий. Нам говорят, что вызов функции-члена является одним из тех исключений. Это дает представление о том, что существуют способы изменения объектов, кроме вызова функции-члена. Я не могу придумать способ.
Как можно изменить объект без вызова функции-члена?
Ответы
Ответ 1
Как можно изменить объект [, указанный выражением rvalue] без вызова функции-члена?
Я знаю только один способ сделать это: привязать объект к ссылке на const
, а затем отбросить const
-ness.
например.
template< class Type >
Type& tempRef( Type const& o ) { return const_cast< Type& >( o ); }
struct S { int x; };
int main()
{ tempRef( S() ).x = 3; }
Это связано с тем, что временный объект не является const
, если он не имеет тип const
, поэтому приведенный выше пример не отбрасывает оригинальную const
-ness (которая будет UB).
EDIT, добавлено: Luc Danton & rsquo; s ответ показал другой (не общий) способ, а именно, где временная конструкция хранит некоторые ссылку или указатель на объект в некотором доступном месте.
Приветствия и hth.,
Ответ 2
Этот считается принятым:
struct T {
int x;
};
int main() {
T().x = 3;
}
Я немного удивлен, что это работает, потому что IIRC LHS op=
должен быть lvalue, но из следующего следует, что even T().x
является Rvalue:
struct T {
int x;
};
void f(int& x) {
x = 3;
}
int main() {
f(T().x);
}
Изменить: Начиная с версии 4.6, GCC предупреждает о T().x = 3
: error: using temporary as lvalue
.
Я не могу придумать другого способа изменить объект класса, кроме как через доступ к члену данных или вызовы функций-членов. Итак, я собираюсь сказать... вы не можете.
Ответ 3
Изменение временного, а не через lvalue для этого временного:
#include <cstring>
class standard_layout {
standard_layout();
int stuff;
};
standard_layout* global;
standard_layout::standard_layout()
{ global = this; }
void
modify(int)
{
std::memset(global, 0, sizeof *global);
}
int
main()
{
modify( (standard_layout {}, 0) );
}
Я не думаю, что правильно предположить, что значения типов классов не изменяются. Теперь я понимаю, что абзац как "для типов некласса, для изменения этого объекта требуется lvalue для объекта".
Ответ 4
Я могу думать об одном способе:
Если ваш класс предоставляет публичные переменные-члены, вы можете напрямую назначить эти переменные-члены. Например:
class A
{
public:
int _my_var;
...
};
int main(int argc, char** argv)
{
A *a = new C();
a->_my_var = 10;
}
Это не очень хороший стиль программирования, но подвергая переменную-члену публике, я не буду защищать или даже предлагать.
Кроме того, если вы можете сделать что-то действительно странное, например, непосредственно написать какой-то адрес в памяти, смещение от указателя на объект класса, но зачем вы это делаете?
Ответ 5
Как можно изменить объект без вызова функции-члена?
Назначение значения одному из видимых элементов данных объекта, конечно.
Ответ 6
Выполнение неявного приведения похоже на вызов функции-члена, также, похоже, работает обработка rvalue ref.
Протестировано следующее в vС++ 10 и g++ 4.4.
struct b { int i; b(int x) : i(x) {} };
struct a { int i; a() : i(0) { } operator b() { return i++ /* this works */, b(i); } };
a f(a&& x) { return x.i++ /* this works */, x; }
int main() { b b = f(a()); /* implicit operator b() cast; b.i will equal 2 */ }
Ответ 7
Функция-член может напрямую изменять элемент, но он также может делегировать эту ответственность:
struct Foo {
int x;
void Bar() { scanf("%d", &x); }
};
Текущая формулировка стандарта имеет то преимущество, что не нужно утверждать, является ли это случаем Bar
изменения объекта. Если мы согласны с тем, что scanf
изменяет объект, то это еще один пример.