У меня возник вопрос по семантике перемещения в рамках POD
типов. Он сложный, поэтому я постараюсь разбить его на подпункты:
В каком состоянии (согласно Стандарту
) находится объект после перемещения? Корректное, но неопределенное? Что это значит?
Если объект является объектом POD
типа, то каков результат операции std::move(object)
?
Относятся ли элементарные типы (int
, float
, double
) к POD
типам?
Если переместить объект POD
типа, то законно ли дальнейшее использование такого объекта? Например:
struct Value
{
int i;
};
Value value;
value.i = 1;
do_something(std::move(value));
// Дальнейшая работа с value.
Буду очень благодарен, если кто-нибудь поможет мне разобраться в этих вопросах.
Не "корректное, но неопределенное", а "корректное, но неспефицированное" (!) (http://eel.is/c++draft/definitions#defns.valid).
Термин "неопределенный" обладает в языке С++ негативной коннотацией (см. "неопределенное поведение"). У стандарта языка С++ нет никаких причин привносить такой оттенок в описание состояния перемещенного объекта. Поэтому именно "неспефицированное", а не "неопределенное".
Упоминание неспецифицированного состояния означает, что все типы разные, и стандарт языка не может однозначно специфицировать конкретные единые правила для всех типов. Каждый тип в рамках семантики перемещения может вести себя по-своему. Язык говорит вам, что за деталями поведения каждого конкретного типа надо обращаться в документацию этого конкретного типа. Документация конкретного типа может частично специфицировать состояние объекта после перемещения, а может и специфицировать его полностью. Более того, даже в рамках конкретного типа состояние объекта после перемещения может зависеть от его состояния до перемещения, то есть от факторов времени выполнения.
Не забывайте при этом, что "перемещение", по определению - более широкая концепция, чем "копирование". Обыкновенное "копирование" является, по определению, частным случаем "перемещения". То есть не будет ничего удивительного в том, если вы, обратившись к спецификации какого-либо типа, обнаружите, что для этого типа "перемещение" эквивалентно "копированию". Если, обратившись к спецификации некоего конкретного типа, вы увидите, что для данного типа семантика перемещения эквивалентна семантике копирования, что означает, что исходный объект после перемещения полностью сохраняет свое исходное корректное состояние.
Также стоит заметить, что термин "неспефицированное поведение" исторически тоже наделялся явным негативным оттенком: не стоит завязываться в своем коде на такое неспефицированное поведение, как, например, порядок вычисления аргументов функции. Однако в случае семантики перемещения ситуация несколько иная: завязываться на документированные свойства перемещенных объектов вполне можно (и нужно), пока вы не выходите за рамки того, что действительно специфицировано.
Для всех типов результатом операции std::move
является xvalue того типа, который был передан в качестве аргумента. std::move
- это лишь преобразование типов. std::move
сам по себе больше ничего не делает. Поэтому никаких особенностей, специфичных для POD, типов у std::move
нет.
Да, относятся.
Да, законно. Для POD типов операция перемещения определена как обыкновенное копирование (см. пункт 1).
Если это объект класса, то его состояние после перемещения зависит только от того, что написано в перемещающем конструкторе / операторе присваивания.
Если это не объект класса (а, например, скаляр), то перемещение делает то же, что и копирование. Исходный объект не меняется.
В "корректное, но неопределенное состояние" попадают некоторые стандартные классы после перемещения. Например std::string
: "left in valid, but unspecified state". (А некоторые нет. Например std::vector
: "guaranteed to be empty()
"`.).
Корректное, но неопределенное? Что это значит?
Нуу, это и значит.
Например, строка может оказаться пустой, а может сохранить свое старое значение - это неопределенное состояние.
Или например, если .size()
возвращает не ноль, то естественно можно спокойно обращаться к строка[0]
, не опасаясь таинственных вылетов или ошибок - состояние строки корректное.
std::move
сам по себе ничего не делает, не важно к POD его применили или нет. Он только превращает выражение в rvalue, чтобы его можно было передать в перемещающий конструктор / оператор присваивания (или еще куда-то, где нужен rvalue).
Относятся ли элементарные типы (int, float, double) к POD типам?
Да. См. определение POD.
Если переместить объект POD типа, то законно ли дальнейшее использование такого объекта?
Да, объект не изменится. См. (1).
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Подскажите, пожалуйста, почему вышеуказанный код показывает, что
Почему-то программа крашится на scanf'е, выдаёт ошибку malloc_consolidate() invalid chunk sizeНо если я поставлю функцию game_logic () в main после остальных, то всё будет...
Я не могу понять что не так с кодом, можете помочь дописать его