Пример класса:
class Move
{
public:
Move(std::string name) : name(name) {};
Move(Move&& move) : name(std::move(move.name)) {};
void Set(std::string&& add)
{
this->name.append(add);
}
void Print()
{
std::cout << this->name << std::endl;
}
private:
std::string name;
};
После выполнения данного кода:
Move move0("string");
Move move1 = std::move(move0);
объект move0
будет иметь вид {name=""}
, но ""
пустая std::string
все равно занимает место в памяти и не освобождает ее сама по себе. Получается, что перемещение более эффективное в некоторых случаях, но при этом старые ссылки остаются "доживать" свой век? Не понятно, что происходит с объектами после использования на них std::move
, хотя казалось бы, что они должны становиться nullptr
.
UPD
Почему есть ситуации в которых после std::move
объект из которого было произведено перемещение, остается без изменений?
int main()
{
std::string str = " Another";
m.Set(std::move(str));
return 0;
}
После std::move(str)
, сам str
остался без изменений.
С++ - это вам не Java. В нем объекты не могут быть null, и не являются ссылками.
что происходит с объектами после использования на них std::move
Строго говоря, move
ничего не делает, кроме как превращает выражение в rvalue ("маскирует" под временную переменную). Это влияет в первую очередь на разрешение перегрузок, и в том числе заставляет срабатывать перемещающие конструктор и оператор присваивания, вместо копирующих. Изменения в объекте вызываются именно перемещающими конструктором или оператором присваивания, куда он передается как аргумент (если это вообще происходит).
Что конкретно происходит с объектом после перемещения из него - зависит того, как написаны перемещающие конструктор и оператор присваивания.
Про стандартные контейнеры, например, говорят что они "are left in valid, but unspecified state". В большинстве реализаций они становятся пустыми, но это не гарантируется.
казалось бы, что они должны становиться nullptr.
Объекты нельзя "сделать nullptr", но можно переформулировать вопрос:
Почему перемещение из объекта не уничтожает его, и требуется дополнительный вызов на нем деструктора?
Я так понимаю, потому что это очень усложнило бы работу компилятора.
Например, для
void foo(std::string s)
{
// ...
}
деструктор всегда вызывается для s
при возврате из функции.
А если перемещение из объекта уничтожало бы его, то компилятору потребовалось бы отслеживать, какие переменные перемещаются, а какие нет. Если переменные перемещаются при определенном условии, то пришлось бы запоминать для каждого объекта, был он перемещен или нет, и в зависимости от этого вызывать или не вызывать на нем деструктор при выходе из функции. Это выглядит сложно.
В языке С++ нет никакой встроенной семантики перемещения. В языке С++ есть только rvalue-ссылки, категории результатов выражений, и связанные с ними правила overload resolution. А что вы сами "слепите" из этих базовых свойств языка - семантику перемещения или что-то другое - определяется только вашим кодом (или, соответственно, библиотечным кодом).
Вы передали переменную str
в метод Set
по rvalue-ссылке, ни внутри метода Set
вы только копируете полученный аргумент add
и никакого физического перемещения данных из него даже и не пытаетесь делать.
Если вы "надеетесь" получить физическое перемещение из add
внутри метода Set
, то это ваша задача - разрешить методу std::string::append
переместить данные из своего аргумента
void Set(std::string&& add)
{
this->name.append(std::move(add));
}
Но и в этом случае фактическое перемещение данных из add
произойдет только в том случае, если сам метод std::string::append
примет решение выполнить перемещение. И здесь я вам могу сказать по секрету, что метод std::string::append
в принципе никогда ничего не перемещает. В большинстве применений std::string::append
это просто-напросто невозможно. Оптимизировать std::string::append
через физическое перемещение возможно только в том случае, когда строка-получатель изначально пуста. А это слишком частная ситуация, чтобы ее оптимизировать. (Я бы лично, возможно, это сделал, но разработчики класса std::string
рассудили по-другому.)
И постарайтесь уяснить, что в С++ обычное копирование - это тоже один из вариантов перемещения. Поэтому рассуждения вроде "объект остался неизменным, значит перемещения не произошло" - бессмысленны.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Пытаюсь собрать пример скриншота на GDI+ на С++ через clexe Вот пример который я пытаюсь собрать
На данный вопрос уже ответили: