C ++ авто та проти авто


88

Чи правильно застосовувати при створенні локальних змінних (const) auto&чи auto?

наприклад:

SomeClass object;
const auto result = object.SomeMethod();

або const auto& result = object.SomeMethod();

Де SomeMethod () повертає непримітивне значення - можливо, інший визначений користувачем тип. Я розумію, що const auto& resultце правильно, оскільки результат, повернутий SomeMethod (), викликав би конструктор копіювання для повернутого типу. Будь ласка, виправте мене, якщо я помиляюся.

А як щодо примітивних типів? Я вважаю, const auto sum = 1 + 2;це правильно.

Чи стосується це також діапазону на основі циклів?

for(const auto& object : objects)

1
Я настійно рекомендую вам прочитати це: safaribooksonline.com/library/view/effective-modern-c/ ... Перші два розділи є безкоштовними та описують вирахування типу шаблону, що, по суті, і autoпрацює (за винятком особливого випадку initializer_lists, які не виводиться в контексті шаблону), потім autoвведіть вирахування.
vsoftco

Відповіді:


102

autoі auto &&охоплюють більшість випадків:

  • Використовуйте, autoколи вам потрібна локальна копія. Це ніколи не дасть посилання. Конструктор копіювання (або переміщення) повинен існувати, але його може не викликати через оптимізацію елісії копії .

  • Використовуйте, auto &&коли вам байдуже, місцевий об’єкт чи ні. Технічно це завжди дасть посилання, але якщо ініціалізатор є тимчасовим (наприклад, функція повертається за значенням), він поводитиметься, по суті, як ваш власний локальний об'єкт.

    Також auto &&не гарантує, що об’єкт можна буде модифікувати. Враховуючи constоб’єкт або посилання, він виведе const. Однак часто передбачається модифікація, враховуючи конкретний контекст.

auto &і auto const &трохи більш конкретні:

  • auto &гарантує, що ви ділитеся змінною з чимось іншим. Це завжди посилання і ніколи не тимчасове.

  • auto const &схожий auto &&, але забезпечує доступ лише для читання.

Що можна сказати про примітивні / непримітивні типи?

Різниці немає.

Чи стосується це також діапазону на основі циклів?

Так. Застосовуючи вищезазначені принципи,

  • Використовуйте auto &&для можливості модифікувати та відкидати значення послідовності в циклі. (Тобто, якщо контейнер не надає подання лише для читання, наприклад std::initializer_list, в такому випадку це буде фактично auto const &.)
  • Використовуйте auto &для змінення значень послідовності значущим чином.
  • Використовувати auto const &для доступу лише для читання.
  • Використовуйте autoдля роботи з (модифікується) копіями.

Ви також згадуєте auto constбез посилання. Це працює, але це не дуже часто використовується, оскільки рідко є перевага лише для читання до того, що вам уже належить.


Саттер каже, що авто відстежує констист
Джессі Пеппер

1
@JessePepper Так. (Хоч трохи дивно звертатися до влади.) Ви маєте на увазі конкретну частину цього?
Potatoswatter

По суті auto&, це хороший вибір. Але використовувати, const auto&коли ви хочете додати стійкості, якої ще немає. auto&&для пересилання, що, на мою думку, відбувається частіше, ніж думає Саттер. Наприклад, ви можете зберегти повернене значення до, auto&&а потім "переслати" його до двох речей, наприклад std :: cout, щоб побачити значення для налагодження, а також передати його якійсь іншій функції. Раніше я користувався авто && частіше, але мене вкусив один-два рази, коли він робив якісь несподівані вчинки. Я би хотів, щоб я більше звертав увагу на те, що пішло не так!
Джессі Пеппер,

@JessePepper Так, auto&&пов’язано з відсутньою мовною функцією, яка повинна дозволити будь-яке твердження поділити на менші. Відсутня частина - продовження життя ... Я доклав чимало зусиль, щоб це виправити, але ніхто не помітив. Не кладіть занадто багато запасів на мудрість :)
Potatoswatter

Про auto const: Може бути природніше писати auto const x = fn (); якщо ви знаєте, що функція не повертає посилання, і ви хочете, щоб об'єкт x не змінювався, щоб уникнути помилок або документувати його використання в області дії. Тим самим ти зазвичай не пишеш: const int & x = 1; Але auto const & дає еквівалентні результати завдяки правилам продовження терміну служби для посилань, оголошених таким чином.
Спасен Джасет,

47

Так, правильно використовувати autoі auto&для локальних змінних. Отримуючи тип повернення функції, це також правильно використовуватиauto& . Це стосується і діапазону на основі циклів.

Загальними правилами користування autoє:

  • Вибирайте auto x коли ви хочете працювати з копіями.
  • Вибирайте auto &x коли ви хочете працювати з оригінальними предметами, і можете змінювати їх.
  • Виберіть, auto const &xколи ви хочете працювати з оригінальними предметами, і не будете їх змінювати.

Ви можете прочитати більше про автоматичний специфікатор тут .


9

autoвикористовує той самий механізм відрахування типу, що і шаблони, єдиним винятком, про який я знаю, що це списки списків-фігурних дужок, які виведені autoякstd::initializer_list , але не виводяться в контексті шаблону.

auto x = expression;

працює, спочатку видаляючи всі посилальні та cv-кваліфікатори з типу виразу з правої сторони, а потім узгоджуючи тип. Наприклад, якщо у вас є, const int& f(){...}то auto x = f();виводить xяк int, а ні const int& .

Інша форма,

auto& x = expression

не знімає cv-кваліфікатори, тому, використовуючи приклад вище, auto& x = f()виводить xяк const int&. Інші комбінації просто додають кваліфікаційні критерії.

Якщо ви хочете, щоб ваш тип завжди виводився за допомогою кваліфікаторів cv-ref, використовуйте скандально відомий decltype(auto)в C ++ 14, який використовує decltypeправила вирахування типу.

Отже, якщо коротко, якщо ви хочете копії, використовуйте auto, якщо хочете посилання, використовуйте auto&. Використовуйте constщоразу, коли ви хочете отримати додаткові можливості const.


EDIT Існує додатковий варіант використання,

auto&& x = expression;

який використовує правила згортання посилань, так само, як у випадку пересилання посилань у коді шаблону. Якщо expressionце значення lvalue, тоді xце посилання на значення lvalue з CV-кваліфікаторами expression. Якщо expressionце значення rvalue, тоді xце посилання на значення rvalue.


@Potatoswatter Дякую, відредаговано. Мені насправді цікаво про cv для rvalues. Чи існує якийсь простий спосіб тестування? І як ви можете отримати сертифікат rvlue? При поверненні функції cv відкидається.
vsoftco

Ні, це не відкидається при поверненні функції. Він відкидається для значень усіх скалярних типів (C ++ 14 [та інші видання] §5 / 6). Ви можете отримати його за допомогою виклику функції або нотації. Xvalues, які відповідають вимогам CV, працюють так само, як і будь-що інше: auto && x = std::move< const int >( 5 );оголошуватимуть int const && x, хоча вони рідко використовуються.
Potatoswatter

@Potatoswatter дякую, ти маєш рацію, моя помилка. Я тестував спочатку з POD, в цьому випадку cv відкидається, і думав, що це загальний випадок. Звичайно, це не слід відкидати, оскільки загалом можна захотіти зберегти cv (наприклад, тому неможливо викликати функцію-non-const при поверненні rvalue).
vsoftco

Викинуто для скалярних типів. POD можуть бути класами. У будь-якому випадку, це хакерський кут перетину моделі виразу та об'єктної моделі.
Potatoswatter

2

Чи правильно при створенні локальних змінних використовувати (const) auto & або auto?

Так. Авто - це не що інше, як виведений компілятором тип, тому використовуйте посилання там, де ви зазвичай використовуєте посилання, та локальні (автоматичні) копії, де ви зазвичай використовуєте локальні копії. Використовувати посилання чи ні, не залежить від вирахування типу.

Де SomeMethod () повертає не примітивне значення - можливо, інший визначений користувачем тип. Я розумію, що const auto & result правильний, оскільки результат, повернутий SomeMethod (), буде викликати конструктор копіювання для поверненого типу. Будь ласка, виправте мене, якщо я помиляюся.

Юридичний? Так, з конст. Найкраща практика? Можливо, ні, ні. Принаймні, не з C ++ 11. Особливо ні, якщо значення, яке повертається з SomeMethod (), вже є тимчасовим. Ви хочете дізнатись про семантику переміщення C ++ 11, елісію копій та оптимізацію поверненого значення: https://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by- значення /

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=199

https://isocpp.org/wiki/faq/ctors#return-by-value-optimization

А як щодо примітивних типів? Я припускаю, що const auto sum = 1 + 2; правильно.

Так, це нормально.

Чи стосується це також діапазону на основі циклів?

для (const auto & object: objects)

Так, це теж добре. Я весь час пишу такий код на роботі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.