C ++, не могу использовать массив или векторы, как мне использовать указатель, чтобы пройти через этот беспорядок? - PullRequest
2 голосов
/ 19 ноября 2009

Мне нужна помощь с указателями и управлением памятью.

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

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

ТНХ, мр

Ответы [ 3 ]

5 голосов
/ 19 ноября 2009

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

std::vector<Base*> objects;

void make_one(void)
{
    Derived d;

    objects.push_back(&d);
}

Потому что, когда функция завершится, класс, на который указывает &d, будет освобожден. Это облегчается динамическим размещением объектов:

std::vector<Base*> objects;

void make_one(void)
{
    Derived *d = new Derived;

    objects.push_back(d); // a-ok
}

Просто не забудьте пройтись по вектору, когда закончите, и набрать delete для них:

struct deleter
{
    template <typename T>    
    void operator()(T* pObject) const
    {
        delete pObject;
    }

}

std::for_each(objects.begin(), objects.end(), deleter());

Если вы можете использовать boost, есть библиотека контейнеров с указателями , которая сделает это за вас. Обратите внимание, вы не можете использовать auto_ptr и пытаться позволить ему сделать это за вас; auto_ptr плохо работает с контейнерами.

Также убедитесь, что в ваших базовых классах есть виртуальные деструкторы:

struct base
{
    virtual ~base(void) {} // important!
}

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

1 голос
/ 19 ноября 2009

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

Массивы предназначены для хранения множества объектов одинакового размера . Проблема с хранением различных объектов в массиве (даже если они получены из одного и того же базового класса) состоит в том, что объекты могут иметь разные размеры.

Вы определенно на правильном пути, думая об указателях.

edit (в ответ на комментарии):

Вы бы смотрели на что-то вроде этого:

BaseClass * array[size];
array[0] = new DerivedClass(...);
array[1] = new OtherDerivedClass(...);
...

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

for (int index = 0; index < size; index++) { delete array[index]; }
0 голосов
/ 19 ноября 2009

Это выглядит очень похоже на проблему, упомянутую здесь: Является ли массив производных таким же, как массив base? . Вы создаете массив производных объектов и пытаетесь получить к нему доступ, как если бы это был массив базы?

Вы можете использовать массив базовых указателей, как это, но учтите, что лучше использовать std::vector<Base*> вместо необработанных массивов:

class Base
{
public:
    virtual ~Base(){}
    virtual void f() {std::cout<<"Base::f()\n";}
};


class Derived1: public Base
{
public:
    ~Derived1(){}
    void f(){std::cout<<"Derived1::f()\n";}
};

class Derived2: public Base
{
public:
    ~Derived2(){}
    void f(){std::cout<<"Derived2::f()\n";}
};


void print(Base** p, int count)
{
    for(int i = 0; i < count; ++i)
    {
        (*p)->f();
        ++p;
    }
}

int main()
{
    Base b;
    Derived1 d1;
    Derived2 d2;

    Base* arr[3];
    arr[0] = &b;
    arr[1] = &d1;
    arr[2] = &d2;

    print(arr, 3);


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