Информация об изменениях

Сообщение Re[3]: Про перемещение (на примере кода) от 15.03.2025 18:54

Изменено 15.03.2025 19:10 rg45

Re[3]: Про перемещение (на примере кода)
Здравствуйте, Shmj, Вы писали:


S>
S>    TrackedClass take() {
S>        return  _trackedClass; // <- тут копия порождается.
S>    }
S>};
S>


Верно.

S>
S>    TrackedClass take() {
S>        TrackedClass tc = std::move(_trackedClass); // <- Копия не порождается.
S>        return tc;
S>    }
S>};
S>


Здесь сначала происходит перемещение содержимого объекта _trackedClass в локальный объект tc. И нужно понимать, что время жизни объекта _trackedClass при этом не заканчивается. Скорлупа этого (под)объекта будет жить, пока живет его полный объект. Также примечательно то, что объект tc является move eligible. Это означает, что, если к нему не будет применена NRVO, то к нему будет применено ещё одно перемещение. Т.е. либо NRVO (что скорее всего), либо второе перемещение, копирования точно не будет.

Как бы то ни было, хотя бы одного перемещения здесь не избежать. Поэтому смысла в этом локальном объекте tc нет никакого. Писать просто: return std::move(_trackedClass); Так и код проще, и потенциальное число перемещений меньше.

S>
S>TrackedClass fun1() {
S>    Wrapper w = Wrapper();
S>    TrackedClass t = w.take(); // <- копия НЕ порождается.
S>    return t;
S>}
S>


Строго говоря, здесь копия может порождаться, а может нет. Стандарт языка не регламентирует число промежуточных копий, это implementation specifics. Но, если NRVO таки было подключено, что скорее всего, тогда никаких дополнительных копий не будет.

К счастью, этот пример можно легко видоизменить так, чтоб вместо необязательной NRVO применялась обязательная RVO:

TrackedClass fun1() {
    Wrapper w = Wrapper();
    return w.take(); // <- копия НЕ порождается СТОПУДОВО!
}


То, что в этом случает не будет промежуточных копий, гарантируется стандартом языка.
Re[3]: Про перемещение (на примере кода)
Здравствуйте, Shmj, Вы писали:


S>
S>    TrackedClass take() {
S>        return  _trackedClass; // <- тут копия порождается.
S>    }
S>};
S>


Верно.

S>
S>    TrackedClass take() {
S>        TrackedClass tc = std::move(_trackedClass); // <- Копия не порождается.
S>        return tc;
S>    }
S>


Здесь сначала происходит перемещение содержимого объекта _trackedClass в локальный объект tc. И нужно понимать, что время жизни объекта _trackedClass при этом не заканчивается. Скорлупа этого (под)объекта будет жить, пока живет его полный объект. Также примечательно то, что объект tc является move eligible. Это означает, что, если к нему не будет применена NRVO, то к нему будет применено ещё одно перемещение. Т.е. либо NRVO (что скорее всего), либо второе перемещение, копирования точно не будет.

Как бы то ни было, хотя бы одного перемещения здесь не избежать. Поэтому смысла в этом локальном объекте tc нет никакого. Лучше писать просто:

    TrackedClass take() { return std::move(_trackedClass); }

Так и код проще, и потенциальное число перемещений меньше.

S>
S>TrackedClass fun1() {
S>    Wrapper w = Wrapper();
S>    TrackedClass t = w.take(); // <- копия НЕ порождается.
S>    return t;
S>}
S>


Строго говоря, здесь копия может порождаться, а может нет. Стандарт языка не регламентирует число промежуточных копий, это implementation specifics. Но, если NRVO таки было подключено, что скорее всего, тогда никаких дополнительных копий не будет.

К счастью, этот пример можно легко видоизменить так, чтоб вместо необязательной NRVO применялась обязательная RVO:

TrackedClass fun1() {
    Wrapper w = Wrapper();
    return w.take(); // <- копия НЕ порождается СТОПУДОВО!
}


То, что в этом случает не будет промежуточных копий, гарантируется стандартом языка.