Новое ключевое слово "auto"; когда оно должно использоваться для объявления типа переменной? [дубликат]


Возможные Дубликаты:
сколько это слишком много с C++0x auto ключевое слово

имеем ли мы (как сообщество) достаточно опыта, чтобы определить, когда и/или злоупотребляют ли авто?

то, что я действительно ищу, - это руководство по лучшей практике

  • когда использовать auto
  • когда этого следует избегать

простые эмпирические правила, которым можно быстро следовать в 80% случаев случаи.

в качестве контекста этот вопрос вызван моим ответом здесь

6 77

6 ответов:

я думаю, когда тип является очень популярным среди со-программистов, которые работают (или будут работать) в ваш проект, то auto можно использовать, например, в следующем коде:

//good : auto increases readability here
for(auto it = v.begin(); it != v.end(); ++it) //v is some [std] container
{
      //..
}

или

//good : auto increases readability here
for(auto it = std::begin(v); it != std::end(v); ++it)//v could be array as well
{
      //..
}

но когда тип не очень хорошо известен и нечасто используется , то я думаю auto кажется, чтобы уменьшить читаемость, например, здесь:

//bad : auto decreases readability here
auto obj = ProcessData(someVariables);

в то время как в первом случае, использование auto кажется очень хорошим и не уменьшает читабельность, и поэтому, смогите быть использовано обширно, но в последнем случае, оно уменьшает читабельность и следовательно не должно быть использовано.


другое место, где auto может использоваться, когда вы используете new1 или make_* функции , такие как здесь:

//without auto. Not that good, looks cumbersome
SomeType<OtherType>::SomeOtherType * obj1 = new SomeType<OtherType>::SomeOtherType();
std::shared_ptr<XyzType> obj2 = std::make_shared<XyzType>(args...);
std::unique_ptr<XyzType> obj2 = std::make_unique<XyzType>(args...);

//With auto. good : auto increases readability here
auto obj1 = new SomeType<OtherType>::SomeOtherType();
auto obj2 = std::make_shared<XyzType>(args...);
auto obj3 = std::make_unique<XyzType>(args...);

здесь это очень хорошо, так как это уменьшает использование клавиатуры, не уменьшая читаемость, так как любой может знать тип объекты создается, просто глядя на код.

1. Избегайте использования new и raw-указатели, хотя.


иногда тип настолько неуместен, что знание типа даже не требуется, например, в шаблон выражения; в самом деле, практически невозможно написать тип (правильно), в таких случаях auto облегчение для программистов. Я написал библиотеку шаблонов выражений, которые могут быть использованы как:

foam::composition::expression<int> x;

auto s = x * x;       //square
auto c = x * x * x;   //cube
for(int i = 0; i < 5 ; i++ )
    std::cout << s(i) << ", " << c(i) << std::endl; 

выход:

0, 0
1, 1
4, 8
9, 27
16, 64

теперь сравните приведенный выше код следующим эквивалентно код, который не использует auto:

foam::composition::expression<int> x;

//scroll horizontally to see the complete type!!
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply>> s = x * x; //square
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply> >, foam::composition::expression<int>, foam::operators::multiply>> c = x * x * x; //cube

for(int i = 0; i < 5 ; i++ )
    std::cout << s(i) << ", " << c(i) << std::endl; 

Как видите, в таких случаях auto делает вашу жизнь легче в геометрической прогрессии. Выражения, используемые выше, очень просты; подумайте о типе некоторых более сложных выражений:

auto a = x * x - 4 * x + 4; 
auto b = x * (x + 10) / ( x * x+ 12 );
auto c = (x ^ 4 + x ^ 3 + x ^ 2 + x + 100 ) / ( x ^ 2 + 10 );

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


Итак, нижняя линия: ключевое слово auto может увеличение или уменьшение ясность и читаемость вашего кода,в зависимости от контекста. Если контекст дает понять, что тип это или, по крайней мере, как он должен использоваться (в случае стандартного итератора контейнера) или знание фактического типа даже не требуется (например, в шаблонах выражений), то auto должно быть используется, и если контекст не делает его ясным и не очень распространен (например, второй случай выше), то лучше быть избежать.

легко. Используйте его, когда вы не важно что это за тип. Например

for (auto i : some_container) {
   ...

все, что меня здесь волнует, это i - Это все, что находится в контейнере.

это немного похоже на typedefs.

typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;

вот, мне все равно h и w поплавки или двойники, только что они любой тип подходит для выражения высоты и веса.

или считать

for (auto i = some_container .begin (); ...

здесь все, что меня волнует, это то, что это подходящий итератор, поддерживающий operator++(), это вроде как утка набрав в этом отношении.

также тип лямбд не может быть записан, так что auto f = []... хороший стиль. Альтернативой является приведение к std::function но это идет с накладными расходами.

Я действительно не могу представить себе "злоупотребление"auto. Самое близкое, что я могу себе представить, это лишение себя явного преобразования в какой-то значимый тип-но вы бы не использовали auto для этого ты создать объект нужного типа.

если вы можете удалить избыточность в коде без побочных эффектов, то это должны будьте добры сделать это.

Я бы применил то же правило, что и для var в C#: использовать его либерально. Это увеличение читабельности. Если тип переменной, на самом деле достаточно важным, чтобы быть четко указано, в каких случаях это следует делать (дух).

тем не менее, я утверждаю, что (особенно в статически типизированных языках) компилятор намного лучше отслеживает типы для нас, чем мы. Большую часть времени точно тип не очень важно в любом случае (в противном случае интерфейсы не будут работать на практике). Более важно знать, какие операции разрешены. Контекст должен нам это сказать.

кроме того, auto на самом деле сможете предотвращение ошибок, предотвращая нежелательные неявные преобразования в инициализации. В общем, утверждение Foo x = y; будет выполнять неявное преобразование, если y не типа Foo и неявное преобразование существует. Это является причиной, чтобы избежать неявных преобразований в первое место. К сожалению, в C++ их уже слишком много.

писать auto x = y; предотвратит эту проблему в принципе.

С другой стороны, должно быть ясно, что когда я выполняю вычисления, которые предполагают то или иное количество байтов в целом, явный тип переменной должен быть известен и должен быть четко указан.

Не все случаи так ясно, но я утверждаю, что большинство из них, и это

  1. в большинстве случаев легко увидеть, должен ли быть известен явный тип, и
  2. потребность в явных типах сравнительно редка.

Эрик Липперт, основной разработчик в команде компилятора C#,заявил Почти то же самое в отношении var.

я думаю, что ответ на ваш первый вопрос вроде нет. Мы знаем достаточно, чтобы собрать некоторые рекомендации о том, когда использовать или избегать auto, но они все еще оставляют довольно много случаев, когда лучшее, что мы можем сейчас сказать, это то, что мы пока не можем дать много объективных советов о них.

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

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

Другим примером может быть, когда вам нужно убедиться, что конкретная переменная имеет определенный тип ради чего-то вроде внешнего интерфейса. Например, рассмотрите возможность применения маски сети к IP-адрес (v4). Для аргументации предположим, что вы работаете с отдельными октетами адреса (например, представляя каждый как unsigned char), поэтому мы в конечном итоге с чем-то вроде octets[0] & mask[0]. Благодаря правилам продвижения типа C, даже если оба операнда unsigned charС, результат, как правило, будет int. Мы нужно результат должен быть unsigned char хотя (т. е. один октет) не int (обычно 4 октета), хоть. Как таковой, в данной ситуации,auto почти конечно, неуместно.

это все еще оставляет много случаев, когда это решение вызова, хотя. Мой собственный тенденция для таких случаев стоит лечить auto по умолчанию, и использовать только явный тип в случаях, которые по крайней мере немного похожи на последний случай, который я привел выше-даже если конкретный тип не нужны для правильной работы, что я действительно люблю!--15-->хочу определенный тип, даже если это может включать неявный преобразование.

моя догадка (но это всего лишь догадка) заключается в том, что со временем я буду наверное как правило, еще больше в этом направлении. По мере того, как я привыкаю к компилятору, выбирающему типы, я обнаружу, что довольно много случаев, когда я в настоящее время думаю я должен указать тип, я действительно не нужно, и код будет просто отлично.

я подозреваю, что многие из нас (и чем старше/опытнее мы, вероятно, тем хуже мы будем об этом) будут используйте явные типы по причинам, которые в конечном счете ведут к некоторому чувству о производительности и вере в то, что наш выбор улучшит производительность. Часть времени мы мая даже быть правым - но как большинство из нас с таким большим опытом обнаружили, наши догадки часто ошибочны (особенно когда они основаны на неявных предположениях), и компиляторы и процессоры, как правило, становятся лучше в таких вещах с течением времени, а также.

я использовал языки с полным выводом типа. Я не вижу причин не ставить auto везде это технически возможно*. На самом деле я уже писал auto i = 0;, где int - это один символ короче, чем auto. Я даже не уверен, что сделал это, потому что внизу: мне не нравится печатать манифест.

*: например auto int[] = { 0, 1, 2, 3 } не работает.

используйте его только с длинными повторяющимися типами, такими как длинные шаблоны и типы лямбда-функций. Постарайтесь избежать этого, если вы можете сделать вещи ясными.