Указатель на вектор объектов, теряющих свою ценность - PullRequest
1 голос
/ 21 мая 2019

У меня есть проект, который я разрабатываю для магистерской работы.В этом проекте у меня есть родительский класс с именем node и некоторые другие дочерние классы, например, класс AND .И у меня также есть класс с именем graph , где узлы хранятся с использованием std :: map.Я пришел к выводу, что мне не нужно использовать std :: map .Используя std :: vector , я бы получил более быстрый доступ к узлам внутри графа.

Класс AND имеет два вектора: один для его входов и другой для его выходов.У меня есть два метода, чтобы добавить указатель узла на один из этих двух векторов.

Когда я перешел с карты на вектор в классе графа, некоторые указатели внутри узлов AND теряют свое значение.

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

class node{
protected:
    unsigned int id;
public:
    virtual void pushOutput(node* param){}
    virtual void pushInput(node* param,bool param_polarity){}
}

class AND : public node{
    vector <node*> inputs;
    vector <node*> outputs;
public:
   void pushOutput(node* param) override;
   void pushInput(node* param,bool param_polarity) override;
}

void AND::pushOutput(node* param){
    this->outputs.push_back(param);
}

//AND::pushInput is omitted, but it is pretty similar to AND::pushOutput except with a bunch of ifs.

class graph {
protected:
//    map<unsigned int,AND> all_ANDS;
    vector<AND> all_ANDS;
public:
    AND* pushAnd(unsigned int index,AND AND_obj); 
    AND* findAnd(unsigned int);
}

AND* graph::pushAnd(unsigned int index, AND AND_obj){
//    std::pair<std::map<unsigned int,AND>::iterator,bool> ret;
//    ret=this->all_ANDS.insert(pair<unsigned int,AND>(index,AND_obj));
    all_ANDS.push_back(AND_obj);
    return &all_ANDS.back();
}

AND* graph::findAnd(unsigned int param){
//    return &this->all_ANDS.find(param)->second;
    return &all_ANDS[param];
}

Обратите внимание, закомментированные строки - это версия кода, используемого для правильной работы.

Использование методов для чтения из файла (некоторые вещи были опущены):

bool polar;
AND* AND_ptr;
unsigned int rhs0;
for(int l=0;l<A;l++)
{
    and_index++;
    AND AND_obj(and_index*2);
    AND_ptr=this->pushAnd(and_index*2,AND_obj);
//reading info from file here and putting on rhs0 and polar.
    AND_ptr->pushInput(findAnd(rhs0),polar);
    findAnd(rhs0)->pushOutput(findAnd(and_index*2));
    findAny(rhs0)->printNode();
}

Если я использую метод graph :: findAnd () , чтобы получить адрес узла и вставить его в вектор другого узла: input или выводит адрес, сохраненный в этих векторах, указывает на некоторый мусор, но только после некоторого времени обработки, он сначала указывает на правильное место, как показывает AND :: printNode () .

Другими словами, graph :: findAnd () возвращает неверный указатель, хотя с версией std :: map он работал просто отлично.

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

Ответы [ 2 ]

1 голос
/ 21 мая 2019

Вы должны рассмотреть вопрос об аннулировании итератора. С cppreference на std::vector::push_back:

Если новый размер () больше емкости (), то все итераторы и ссылки (включая итератор конца-в-конце) становятся недействительными. В противном случае только последний итератор становится недействительным.

Здесь «ссылки» используются в более широком смысле, то есть указатели на элементы также становятся недействительными. Причина в том, что std::vector гарантирует сохранение своих данных в непрерывном блоке памяти, следовательно, предыдущие элементы могут перемещаться, когда вы нажимаете новые.

Я слишком плохо понимаю ваш код, чтобы давать больше советов. Просто отметьте, что std::list не делает недействительными итераторы при добавлении новых элементов (то же самое относится и к std::map). Однако это происходит по цене, которую обычно не стоит платить (отсутствие данных с std::list не является убийцей). С другой стороны, если целью контейнера является включение ссылок на элементы без аннулирования, это может быть правильным выбором.

0 голосов
/ 21 мая 2019

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

.

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

Вы можете, например, использовать vector из std::shared_ptr s для объектов. Затем вы можете хранить дополнительные shared_ptr s для этих объектов в других коллекциях.

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