C ++ векторные элементы доступа - PullRequest
5 голосов
/ 26 января 2012

Как получить доступ к элементам из myVector, как если бы я делал с массивами (for(i = 0; i < n; i++) cout << v[i] << " ";)

Мой код:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Month
{
public:
    char *name;
    int nr_days;
    Month(char* c, int nr) : name(c), nr_days(nr){};
    ~Month() { /* free(name); */}
};

int main()
{
    Month January("January", 31);
    Month February("February", 28);
    Month March("March", 31);
    Month April("April", 30);
    Month May("May", 31);
    Month June("June", 30);
    Month July("July", 31);
    Month August("August", 31);
    Month September("September", 30);
    Month Octomber("Octomber", 31);
    Month November("November", 30);
    Month December("December", 31);

    vector<Month> *myVect = new vector<Month>;
    myVect->push_back(January);
    myVect->push_back(February);
    myVect->push_back(March);
    myVect->push_back(April);
    myVect->push_back(May);
    myVect->push_back(June);
    myVect->push_back(July);
    myVect->push_back(August);
    myVect->push_back(September);
    myVect->push_back(Octomber);
    myVect->push_back(November);
    myVect->push_back(December);

    for(vector<Month>::const_iterator i = myVect->begin(); i != myVect->end(); i++)
    {
        /*
        Month myMonth = i;
        cout << myMonth.name << " " << myMonth.nr_days << endl;
        */
    }

    free(myVect);
    return 0;
}

Я хотел бы быть что-то вроде алгоритма foreach: foreach(Month in myVect) cout << ...

И еще один вопрос: почему он дает мне ошибку времени выполнения в деструкторе, если я раскомментирую свою строку?

Ответы [ 6 ]

7 голосов
/ 26 января 2012

Хорошо, здесь много проблем.

  1. Вы объявляете myVect как указатель на вектор.Это не нужно.Одним из основных преимуществ использования вектора является то, что вам не нужно беспокоиться об управлении памятью, поскольку vector делает это за вас.Вы выделяете вектор в стеке, но внутренне он выделяет память, используемую для хранения содержащихся в нем элементов.

  2. Вы никогда не инициализируете указатель.Вы вызываете неопределенное поведение, так как этот указатель недопустим.Для инициализации указателя вы используете new.Все, что у вас есть, это недопустимый указатель, выделенный стеком, который не указывает на vector в куче.РЕДАКТИРОВАТЬ: Я только что понял, что new был отредактирован, так что вы можете игнорировать этот.Тем не менее, он вообще не должен быть указателем.

  3. Вы используете free для освобождения класса C ++ (который вы никогда не выделяли для начала ...).Не.Это не C, вы используете new и delete для управления памятью (когда это необходимо!) В C ++.free не вызывает деструкторы, он просто освобождает кусок памяти.delete, с другой стороны, делает то, что умеет работать со сложными типами C ++. Никогда mix new / delete с malloc / free.

  4. myVect->begin() возвращает const_iterator, а не T(т. е. в данном случае это не объект Month).Разыменование итератора с помощью оператора * приведет к текущему объекту итерации, поэтому:


Month myMonth = *i  // <--- IMPORTANT!

В качестве отступления, если вы собираетесь зацикливатьсячасто над вектором вам может понадобиться typedef итератор, чтобы уменьшить многословность, то есть

typedef vector<Month>::const_iterator cmonth_iter;

Теперь вы можете написать

for(cmonth_iter i = myVect.Begin(); i != myVect.end(); ++i )
{
    Month m = *i;
    // do stuff with m    
}
2 голосов
/ 26 января 2012

Вы можете получить доступ к элементам, используя итератор, используя оператор *:

for(vector<Month>::const_iterator i = myVect->begin(); i != myVect->end(); i++)
{
    Month myMonth = *i;
    cout << myMonth.name << " " << myMonth.nr_days << endl;
}

Кроме того, вы никогда не выделяете vector в своем коде.Вы не должны использовать free() для указателя, который вы не получили от malloc() ранее.В противном случае поведение не определено, и во время выполнения, вероятно, произойдет ошибка в точке, которую вы называете free().

Попробуйте это:

vector<Month> *myVect = new vector<Month>;
...
delete myVect;
1 голос
/ 26 января 2012

Если вы удалите ошибку унифицированного указателя, изменив:

vector<Month> *myVect;

до:

vector<Month> myVect;

Тогда это будет работать. (Как только вы определите ostream << Month)

for(i = 0; i < myVect.size(); i++)
 cout << v[i] << " ";
0 голосов
/ 26 января 2012

Вы можете использовать оператор стрелки с итераторами ...

for(vector<Month>::const_iterator i = myVect->begin(); i != myVect->end(); i++)
{
    cout << i->name << " " << i->nr_days << endl;
}

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

Обратите внимание, что ваш код UB (неопределенное поведение), потому что вы используете указатель на вектор, но не выделяете его. Между прочим, использование указателя в этом случае бессмысленно, код будет правильным и более простым:

vector<Month> myVect;
myVect.push_back(January);
myVect.push_back(February);
...
for(vector<Month>::const_iterator i = myVect.begin(); i != myVect->end(); ++i)
  ...

Мое предложение также состоит в том, чтобы не пытаться изучать C ++, просто экспериментируя с компилятором (что, как мне кажется, вы пытаетесь сделать).

C ++ является мощным, но также сложным и, к сожалению, довольно нелогичным и асимметричным во многих частях (из-за его истории развития). Добавьте к этому, что когда вы делаете ошибку (например, не выделяете вектор в исходном коде), вы не можете ожидать, что компилятор вам поможет, и даже во время выполнения программа может делать НИЧЕГО, в том числе, очевидно, работать так, как вы ожидали (наихудшая возможная вещь) , Это комбо смертельно.

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

0 голосов
/ 26 января 2012

Вы объявляете myVect как указатель, но никогда не выделяете его, это доставит вам много хлопот. Просто бросьте * и все будет в порядке.

Если вы настаиваете, вы можете использовать индекс так же, как если бы вы использовали массив:

for(int i = 0; i < myVect.size(); i++)
{        
    Month myMonth = myVect[i];
    cout << myMonth.name << " " << myMonth.nr_days << endl;
}

Хотя я бы предпочел использовать итераторы, как вы это сделали - всего лишь одно простое исправление:

    Month myMonth = *i;
0 голосов
/ 26 января 2012
  1. У вас есть указатель myVect, но вы никогда не назначаете ему значение перед использованием (включите предупреждения компилятора).вы должны сделать что-то вроде myVect = new vector<Month>().(или не указывайте его и не меняйте -> на .).В остальном ваша реализация "foreach" выглядит нормально.И вы также можете использовать [] для доступа к элементам.

  2. Вы освобождаете константы, вы не выделяете их, поэтому вам также не нужно их освобождать.*

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