Две ошибки стоимостью в два дня отладки


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

Вот первая ошибка:
// создаем массив векторов
std::vector<std::vector<SomeStruct> > theVector;
std::vector<SomeStruct> emptyVector;
for (int i = 0; i < 100; i++)
  theVector.push_back(emptyVector);
Я рассуждал примерно так: vector — это объект, хранящий указатели на область памяти, где фактически хранятся данные. Но, для пустого вектора, эти указатели будут равны NULL. А значит, мы можем многократно копировать пустой вектор. Но STLport не был бы STLport’ом, если бы все было так просто. Оказывается, vector в одном из полей хранит указатель на самого себя. И инициализируется этот указатель во время работы конструктора. Поэтому правильно создавать вектор векторов так:
// создаем массив векторов
std::vector<std::vector<SomeStruct> > theVector;
for (int i = 0; i < 100; i++)
  theVector.push_back(std::vector<SomeStruct>());
Теперь о второй ошибке. 
std::vector<SomeStruct>& v = theVector[index1];
// поработали немного с этим вектором, потом понадобился другой
v = theVector[index2];
Все, приплыли! Так делать категорически нельзя! Только я это понял через день отладки, когда заменил ссылки на указатели, которые почему-то 🙂 работали правильно:
std::vector<SomeStruct>* pv = &theVector[index1];
pv = &theVector[index2]; // а вот так делать можно!
Важное отличие ссылки от указателя заключается в том, что в ссылочную переменную адрес объекта заносится один и только один раз — при ее инициализации. Все! Любые другие присваивания ссылочной переменной — это присваивания объекту, хранящемуся по этому адресу. Но с точки зрения синтаксиса, правая и левая части выглядят одинаково в обоих случаях, однако действия, выполняемые при этом, принципиально разные. Все зависит от того, находится ли слева от левой части тип данных или нет.
Запись опубликована в рубрике Uncategorized. Добавьте в закладки постоянную ссылку.

3 отзыва на “Две ошибки стоимостью в два дня отладки

  1. А почему не
    std::vector<std::vector > theVector(100);
    ?

  2. Вот об этом я тогда как-то не подумал, спасибо! 🙂

  3. Anonimous:

    Такая ошибка и 10 лет опыта несовместимы.

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