TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #712 4.2K
​​decltype(auto) vs auto&&. Вывод типа возвращаемого значения
#опытным

Второе место, в котором целесообразно использовать decltype(auto) и auto&& - это автоматический вывод типа возвращаемого значения функции. Вот тут между ними есть важные различия, которые мы сейчас и обсудим.

decltype(auto) bar() {
int i;
int& ref = i;
return ref;
}

decltype(auto) bar1() {
int i = 42;
return i;
}

decltype(auto) bar2() {
return 42;
}

decltype(auto) bar3() {
int i;
return std::move(i);
}

auto&& baz() {
int i;
int& ref = i;
return ref;
}

auto&& baz1() {
int i = 42;
return i;
}

auto&& baz2() {
return 42;
}

auto&& baz3() {
int i;
return std::move(i);
}


Вот 2 семейства функций, которые возвращают объекты разной ссылочности и выводит тип возвращаемого значения по-разному. Давайте с помощью cppinsights посмотрим, какие реально типы возвращаемых значений выведутся:

int & bar() {
int i;
int & ref = i;
return ref;
}

int bar1() {
int i = 42;
return i;
}

int bar2() {
return 42;
}

typename std::remove_reference<int &>::type && bar3() {
int i;
return std::move(i);
}

int & baz() {
int i;
int & ref = i;
return ref;
}

int & baz1() {
int i = 42;
return i;
}

int && baz2() {
return 42;
}

typename std::remove_reference<int &>::type && baz3() {
int i;
return std::move(i);
}


Единственная разница появляется, когда мы возвращаем из функции lvalue или prvalue объект. В этом случае auto&& выводит тип правой ссылки, а decltype(auto) - обычный бессылочный lvalue объект. И в этом факте вся проблема. Может быть ее не видно сейчас, когда мы возвращаем целочисленный литерал. Но задние ряды уже догадались. Давайте же перейдем к реальной проблеме:

struct CLASS {
CLASS(int i) : num{i} {
std::cout << "ctor " << num << std::endl;
}
~CLASS() {
std::cout << "dtor " << num << std::endl;
}
int num;
};

decltype(auto) get_class_decltype() {
return CLASS(0);
}

auto&& get_class_auto() {
return CLASS(42);
}

int main() {
decltype(auto) a = get_class_decltype();
std::cout << "separator" << std::endl;
decltype(auto) b = get_class_auto();
std::cout << "separator" << std::endl;
}


Делаем простой класс, чтобы отследить его время жизни. И два варианта функции, которые возвращают rvalue объекты. Вот вывод для этого кода:
Вывод:
ctor 0
separator
ctor 42
dtor 42
separator
dtor 0


Здесь видно, что деструктор первого объекта вызывается в самом конце. При присваивании результата функции get_class_decltype() локальному объекту происходит оптимизация copy-elision, благодаря которой объект созданный внутри функции "бесшовно" становится локальным объектом caller'а без всяких мув- и копи- конструкторов.

А вот деструктор второго объекта, который мы планировали возвращать из get_class_auto, вызывается сразу после конструирования. На самом деле сигнатура функции get_class_auto выглядит так:

CLASS&& get_class_auto();


Мы пытаемся вернуть локальный объект функции через правую ссылку. Такое в С++ хоть и скомпилируется, но приведет к висячей ссылке и в последствии к UB при использовании ссылки.

Аналогичное будет происходить, если возвращать lvalue.

Какой вывод?

Если вам нужен вывод типов в возвращаемом значении функции - всегда используйте в типе возвращаемого значения функции decltype(auto) вместо auto&&, особенно в шаблонном коде. На это кстати есть еще одна причина, о которой речь пойдет в следующем посте.

Be safe. Stay cool.

#cppcore
  • 👍 24
  • ❤ 10
  • 🔥 7
More from @grokaemcpp
  1. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  2. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  3. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  4. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  5. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  6. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
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 →