суббота, 13 апреля 2013 г.

Ключевое слово auto в C++: палка о двух концах?


В недавно вышедшем стандарте C++11 появилось новое ключевое слово auto, точнее сказать оно поменяло семантику. Это ключевое слово было в языке и раньше и обозначало автоматические (т.е. локальные) переменные. В новом же стандарте это ключевое слово предназначено для автоматического выведения типа переменной. Многие профессиональные программисты только рады нововведению, однако, как это часто бывает, - это палка о двух концах.
Давайте разберемся почему и зачем в языке C++ было добавлено это нововведение?
Для начала рассмотрим такой код:

#include <map>
#include <vector>
#include <string>
 
int main()
{
   using namespace std;
   map<string, vector< pair<int,double> > > parser;
   // ...
   map<string, vector< pair<int,double> > >::const_iterator it =
   parser.begin();
   for (; it != parser.end(); ++it) {
       // ...
   }
   return 0;
}
 
 

Видите нам пришлось написать весь этот громоздкий код (особенно в строке 10), только потому, что C++ язык строго типизированный и мы обязаны в объявлении переменной указать ее точный тип. Обычно такие проблемы решались через ключевое слово typedef, которое создает псевдоним типа:

#include <map>
#include <vector>
#include <string>
 
int main()
{
   using namespace std;
   typedef pair<int, double> pair_t;
   typedef vector<pair_t> vector_t;
   typedef map<string, vector_t> map_t;
   map_t parser;
   // ...
   map_t::const_iterator it = parser.begin();
   for (; it != parser.end(); ++it) {
      // ...
   }
   return 0;
}
 

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

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

#include <vector>
 
int main()
{
   auto vctr = new std::vector<int>();
   vctr->push_back(3);
   int i = vctr[0]; // will not compiled
   //...
   delete vctr;
   return 0;
}
 
Что не так в этом коде? Да много чего:
  • Объявление auto равносильно std::vector<int>*, то есть объявляет тип "указатель на объект vector<int>".
  • Далее, vctr[0] равносильно *(vctr + 0), то есть *vctr, то есть разыменованному указателю на std::vector<int>.
  • Поскольку мы пытаемся присвоить результат разыменования указателя переменной типа int, то возникает ошибка компиляции, поскольку такое преобразование недопустимо в пределах этой единицы трансляции.
Как видите ошибиться нетрудно. Кроме этих недостатков есть еще один, который лично меня очень часто останавливает от использования этой новой возможности: до сих пор не все компиляторы поддерживают в полном объеме новый стандарт, и когда будут еще вопрос. Так что я бы сказал так: будьте внимательны и используйте auto с осторожностью и только по необходимости!

Комментариев нет:

Отправить комментарий