Современные компиляторы и NRVO
От: _NN_ www.nemerleweb.com
Дата: 01.03.24 16:22
Оценка:
Насколько вы полагаетесь на оптимизацию компилятора ?

Скажем даже MSVC подтянулся с оптимизацией: MSVC Improving Copy and Move Elision.
Однако, стандарт не гарантирует нам отсутствие копирования в отличии от гарантий временного объекта.

В идеале хотелось бы проверку на этапе компиляции в отсутствии копирования.
С другой стороны, можно всегда приводить к rvalue и получить гарантировано отсутствие копирования, правда с гарантированным перемещением, которого не будет в случае NRVO.

struct MyType { ... };

MyType might_copy() {
 MyType m;
 // много-много кода
 return m;
}

MyType always_move() {
 MyType m;
 // много-много кода
 return std::move(m);
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Современные компиляторы и NRVO
От: kov_serg Россия  
Дата: 01.03.24 16:33
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Насколько вы полагаетесь на оптимизацию компилятора ?


будьте проще
void do_something(MyType &m) {
  // много-много кода
}
Отредактировано 01.03.2024 16:33 kov_serg . Предыдущая версия .
Re: Современные компиляторы и NRVO
От: andrey.desman  
Дата: 01.03.24 16:36
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>С другой стороны, можно всегда приводить к rvalue и получить гарантировано отсутствие копирования, правда с гарантированным перемещением, которого не будет в случае NRVO.


Если компилятор не смог NRVO, то он и так будет пытаться сделать через move (если он нормальный компилятор, конечно). Так что смысла в return std::move(...) нет если типы одинаковые.
Отредактировано 01.03.2024 16:40 andrey.desman . Предыдущая версия .
Re: Современные компиляторы и NRVO
От: reversecode google
Дата: 01.03.24 16:58
Оценка: +1
вообще забудьте за это
начиная с с++17 изза кажеться полухина
теперь везде сopy elision
Re: Современные компиляторы и NRVO
От: rg45 СССР  
Дата: 01.03.24 17:01
Оценка: +1
Здравствуйте, _NN_, Вы писали:

_NN>
_NN>MyType always_move() {
_NN> MyType m;
_NN> // много-много кода
_NN> return std::move(m);
_NN>}
_NN>


А вот это как раз то, чего делать не стоит. Здесь и без std::move копмилятор будет использовать перемещение. И это не какая-то там оптимизация, а требование стандарта языка:

http://coliru.stacked-crooked.com/a/73e49fce4ce61b1c

struct MyType
{
    MyType() = default;
    MyType(const MyType&) = default;
    
    MyType(MyType&&) = delete;
};

MyType might_copy() {
 MyType m;
 // много-много кода
 return m; // error: use of deleted function 'MyType::MyType(MyType&&)' 
}


Но только у компилятора, помимо перемещения есть также еще и опция NRVO. Но вот когда ты используешь std::move, ты эту возможность отсекаешь.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Современные компиляторы и NRVO
От: rg45 СССР  
Дата: 01.03.24 17:04
Оценка:
Здравствуйте, reversecode, Вы писали:

R>вообще забудьте за это

R>начиная с с++17 изза кажеться полухина
R>теперь везде сopy elision

Да как бы не так. Copy elision вытеснил только RVO, а NRVO как был оптимизацией, так и осталсся. И требует доступности move семантики. Вот здесь пример: http://rsdn.org/forum/cpp/8702330.1
Автор: rg45
Дата: 01.03 20:01
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 01.03.2024 17:06 rg45 . Предыдущая версия . Еще …
Отредактировано 01.03.2024 17:05 rg45 . Предыдущая версия .
Re[3]: Современные компиляторы и NRVO
От: reversecode google
Дата: 01.03.24 17:08
Оценка:
https://en.cppreference.com/w/cpp/language/copy_elision

This variant of copy elision is known as NRVO, "named return value optimization." In the initialization of an object, when the source object is .

Re[4]: Современные компиляторы и NRVO
От: rg45 СССР  
Дата: 01.03.24 17:25
Оценка:
Здравствуйте, reversecode, Вы писали:

R>https://en.cppreference.com/w/cpp/language/copy_elision

R>

R>This variant of copy elision is known as NRVO, "named return value optimization." In the initialization of an object, when the source object is .


Угу, и называется это non-mandatory copy/move elision. Ты заголовок-то прочитай, на который ссылку даешь.

Ты понимаешь смысл слов "non-mandatory" и "optimization"? Если не понимаешь, то я поясню — это означает, что компилятор может выполнить эту ОПТИМИЗАЦИЮ, а может не выполнить — по своему усмотрению. Поэтому и доступность move семантики для NRVO является обязательной. В отличие от mandatory copy/move elision, которая позволяет возвращать по значению объекты non-copyable and non-moveable классов.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 01.03.2024 17:26 rg45 . Предыдущая версия .
Re: Современные компиляторы и NRVO
От: T4r4sB Россия  
Дата: 01.03.24 17:28
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>MyType always_move() {

_NN> MyType m;
_NN> // много-много кода
_NN> return std::move(m);
_NN>}
_NN>[/c]

Кстати если у класса нет отдельного мув-конструктора, но есть свой копи-конструктор (а в древнем проекте, написанном до 11 года, это вполне вероятно), то мув по дефолту делается через копирование. Так что есть риск что будет лишнее копирование
Re[5]: Современные компиляторы и NRVO
От: reversecode google
Дата: 01.03.24 18:47
Оценка: -1
я просто не верю в мифы про немножко беременность
и если компилятор может сделать какую то хрень
то он ее обязательно сделает и сделает как можно чаще
Re[6]: Современные компиляторы и NRVO
От: rg45 СССР  
Дата: 01.03.24 19:33
Оценка: +2
Здравствуйте, reversecode, Вы писали:

R>я просто не верю в мифы про немножко беременность

R>и если компилятор может сделать какую то хрень
R>то он ее обязательно сделает и сделает как можно чаще

В какие еще мифы? Я тебе конткретный пример привел:

Вот так можно (mandatory copy/move elision, aka RVO):

MyType might_copy() {
 return MyType{};
}


А вот так нельзя (non-mandatory copy/move elision, aka NRVO):

MyType might_copy() {
 MyType m;
 // много-много кода
 return m; // error: use of deleted function 'MyType::MyType(MyType&&)' 
}


И в этом принципиальное отличие RVO от NRVO и обязательного требования от оптимизации. А ты мне тут про какую-то свою веру рассказываешь

Изменения в части copy/move elision коснулись только RVO — оно перестало быть оптимизацей и стало обязательным требованием. А NRVO как было необязательной оптимизацей в C++03, так и осталось необязательной оптимизацией в C++23.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 01.03.2024 19:46 rg45 . Предыдущая версия .
Re[2]: Современные компиляторы и NRVO
От: _NN_ www.nemerleweb.com
Дата: 03.03.24 09:31
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, _NN_, Вы писали:


_NN>>
_NN>>MyType always_move() {
_NN>> MyType m;
_NN>> // много-много кода
_NN>> return std::move(m);
_NN>>}
_NN>>


R>А вот это как раз то, чего делать не стоит. Здесь и без std::move копмилятор будет использовать перемещение. И это не какая-то там оптимизация, а требование стандарта языка:

используешь std::move, ты эту возможность отсекаешь.

Точно ли стандарт гарантирует использование конструктора перемещения прежде всего или всё же на усмотрение компилятора ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Современные компиляторы и NRVO
От: rg45 СССР  
Дата: 03.03.24 11:41
Оценка: 22 (1)
Здравствуйте, _NN_, Вы писали:

_NN>Точно ли стандарт гарантирует использование конструктора перемещения прежде всего или всё же на усмотрение компилятора ?


По крайней мере, если полагаться на формулировки стандартов С++17 и C++20, то точно, (хотя они и несколько отличаются друг от друга):

https://timsong-cpp.github.io/cppwp/n4861/class.copy.elision#3

Здесь, конечно, здорово сбивает столку фраза "might be" в первом предложении абзаца:

An implicitly movable entity is a variable of automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. In the following copy-initialization contexts, a move operation might be used instead of a copy operation...


Но если прочитать абзац до конца, становится понятно, что это "might be" вовсе не является эквивалентом "на усмотрение компилятора", а относится к различным возможным исходам достаточно четко описанной процедуры, которую должен выполнить компилятор:

overload resolution to select the constructor for the copy or the return_­value overload to call is first performed as if the expression or operand were an rvalue. If the first overload resolution fails or was not performed, overload resolution is performed again, considering the expression or operand as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor or the return_­value overload to be called if elision is not performed, and the selected constructor or return_­value overload must be accessible even if the call is elided. — end note]


То есть, компилятор ДОЛЖЕН сперва попытаться обработать выражение под return как rvalue и только затем уже как lvalue. Тут нужно заметить, что если на первом шаге находится конструктор перемещения, который явно помечен как удаленный, то вторая попытка даже не выполняется.

В С++23 снова перетасовали все формулировки, снова нужно разбираться, чтоб понять, что именно изменилось. Но я не думаю, что этот принцип будет отменен.

P.S. Ну и такое еще, чисто обывательское соображение: это было бы совсем странно, если бы они требовали обязательной доступности семантики перемещения объекта в условиях, когда попытка использования этой самой семантики не является обязательной.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 03.03.2024 12:55 rg45 . Предыдущая версия .
Re[2]: Современные компиляторы и NRVO
От: rg45 СССР  
Дата: 03.03.24 17:31
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Кстати если у класса нет отдельного мув-конструктора, но есть свой копи-конструктор (а в древнем проекте, написанном до 11 года, это вполне вероятно), то мув по дефолту делается через копирование. Так что есть риск что будет лишнее копирование


Да, но в этом случае и использование std::move ничего не изменит. В этой же теме, как я понял, главный вопрос — нужно использовать std::move в return expression, или не нужно.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: Современные компиляторы и NRVO
От: T4r4sB Россия  
Дата: 03.03.24 21:03
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Да, но в этом случае и использование std::move ничего не изменит.


Изменит, он сделает хуже

https://ideone.com/DfhD8o
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.