C ++ auto и vs auto

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)
Rohunb
источник
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без ссылки. Это работает, но не очень часто используется, потому что доступ только для чтения к тому, что у вас уже есть, редко дает преимущество.

Potatoswatter
источник
Саттер говорит, что автоматически и отслеживает постоянство
Джесси Пеппер
1
@JessePepper Да. (Хотя апеллировать к властям немного странно.) Вы имеете в виду конкретную часть этого?
Potatoswatter
По сути auto&, это хороший выбор. Но используется, const auto&когда вы хотите добавить константности, которой еще нет. auto&&предназначен для пересылки, что, я думаю, случается чаще, чем думает Саттер. Например, вы можете захотеть сохранить возвращаемое значение, auto&&а затем «переслать» его двум вещам, например std :: cout, чтобы увидеть значение для отладки, а также передать его какой-либо другой функции. Раньше я чаще использовал auto &&, но меня укусило один или два раза, когда он делал какие-то неожиданные вещи. Хотел бы я больше обращать внимание на то, что пошло не так!
Джесси Пеппер
@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использует тот же механизм вывода типов, что и шаблоны, единственное известное мне исключение - это списки brace-init, которые выводятся с помощью autoas 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.

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

Итак, в двух словах, если вам нужны копии, используйте auto, если вам нужны ссылки, используйте auto&. Используйте constвсякий раз, когда вам нужна дополнительная constсвобода.


ИЗМЕНИТЬ Существует дополнительный вариант использования,

auto&& x = expression;

который использует правила сворачивания ссылок, как и в случае пересылки ссылок в коде шаблона. Если expression- lvalue, то xэто ссылка на lvalue с квалификаторами cv expression. Если expressionэто rvalue, то xэто ссылка на rvalue.

vsoftco
источник
@Potatoswatter Спасибо, отредактировал. Я действительно интересуюсь резюме для rvalues. Есть ли простой способ тестирования? И как получить rvalue с квалификацией cv? При возврате функции cv отбрасывается.
vsoftco
Нет, он не сбрасывается при возврате функции. Он отбрасывается для prvalue всех скалярных типов (C ++ 14 [и другие редакции] §5 / 6). Вы можете получить его, используя вызов функции или обозначение приведения. Квалифицированные cv значения x работают так же, как и все остальное: auto && x = std::move< const int >( 5 );будет объявлять int const && x, хотя они редко используются.
Potatoswatter
@Potatoswatter спасибо, вы правы, моя ошибка. Сначала я протестировал POD, и в этом случае cv отбрасывается, и подумал, что это общий случай. Конечно, от него не следует отказываться, поскольку в общем случае может потребоваться сохранить cv (например, чтобы нельзя было вызвать неконстантную функцию-член при возврате rvalue).
vsoftco
Отброшено для скалярных типов. POD могут быть классами. Во всяком случае, это хакерский уголок на пересечении модели выражения и объектной модели.
Potatoswatter
2

Правильно ли при создании локальных переменных использовать (const) auto & или 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; правильно.

Да, это нормально.

Применимо ли это также к циклам на основе диапазона?

for (const auto & object: объекты)

Да, это тоже нормально. Я все время пишу такой код на работе.

tweej
источник