TGViewer
this->notes. this->notes. @thisnotes · 4.51K subscribers
Post #200 2.34K
#cpp

RVO/NRVO 2/2.

Как понять, убиваете ли вы NRVO? Можно сделать такой же класс, который выводит операции со своими конструкторами. В случае некоторых компиляторов (clang) можно ещё одним способом, о котором рассказали в комментариях в посте про этапы компиляции. На этапе семантического разбора компилятор производит всякие проверки на корректность типов в выражениях и подобном. Например у clang к основному условия про совпадение типов для NRVO ещё проверяется, правда ли, что во всех return возвращается одна и та же локальная переменная. Посмотрим на пример (gb):

void func1(std::optional<std::string>&);
std::string get_s();
void func2(std::string&);

std::optional<std::string> f(bool flag) {
std::optional<std::string> null;
func1(null);
if (flag) return null;
// (1)
std::string s = get_s();
func2(s);
return s; // (2)
}


Во-первых, корректно ли мы в (2) возвращаем s? Ответ нет. Лучше мувнуть. Потому что в данном случае будет вызван конструктор std::optional<std::string>(const std::string&) для RVO. Если же мувать, получим std::optional<std::string>(std::string&&). Хотя с C++20 мувать уже необязательно.

Во-вторых, случится ли NRVO в (1)? В данном случае нет, т.к. эта локальная переменная не возвращается во всех return. Однако если начать возвращать её и во втором return, то в AST можно будет увидеть строчку:

`-VarDecl <col:5, col:32> col:32 used null 'std::optional<std::string>':'std::optional<std::basic_string<char>>' nrvo callinit destroyed

С пометкой nrvo. Получается, можно сэмулировать структуру вашего кода и посмотреть на AST. Оч прикона кмк.

Если подумать, почему же одна и та же локальная переменная во всех return важна, то всё становится понятно: компилятор уверен, что эту переменную в памяти можно создавать сразу в return slot результата функции. В обратном случае это неверно, так что переменная null копируется.

Круто🤭

Если вы об этом паритесь, общие рекомендации такие:
1. Пытаться возвращать prvalue.
2. Возвращать одну и ту же локальную переменную во всех return.

Аналогичные правила примерно применимы и к исключениям, о которых два других пункта в стандарте. Но, честно говоря, если вы пытаетесь оптимизировать и так не очень производительные исключения, что-то пошло не так : )

Тут можно посмотреть хороший небольшой доклад про то, как это всё работает (с чуть бОльшим количеством технических деталей) и с примерами, когда это не работает.
Ещё можно посмотреть вот это бомбическое видео.
  • ❤ 8
  • 🔥 4
  • 🤯 1
More from @thisnotes
  1. Sep 25, 2026Спасибо большое!
  2. Sep 25, 2026Post #525
  3. Sep 25, 2026Post #524
  4. Sep 25, 2026Post #523
  5. Sep 25, 2026Post #522
  6. Sep 25, 2026Post #521
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →