вектор — C ++ exc_bad_access доступ к строковому полю из наведенного объекта в unordered_map

Я пытаюсь сохранить вектор быстрого доступа следующим образом:

MyClass.h:

class MyClass{
private:
std::vector<Stuff> myStuffList;
std::tr1::unordered_map<std::string,Stuff*> myStuffListIndex;
...
public:
void addToStuffList(std::string key,Stuff stuff);

};

MyClass.cpp:

...
void MyClass::addToStuffList(std::string name, Stuff stuff){
myStuffList.push_back(stuff);//our man is guaranteed to be at tail
myStuffListIndex[name] = &myStuffList[myStuffList.size()-1];//store
//pointer to object that we just copy-constructed at tail of list
}

Stuff.h:

class Stuff{
private:
std::string name;
public:
Stuff();
Stuff(const Stuff&);
Stuff& operator=(const Stuff&);
...

};

Stuff.cpp:

Stuff::Stuff() : name(""){}
Stuff::Stuff(const Stuff& other){
if(this != &other){
this->name = other.name;
}
}
Stuff& Stuff::operator=(const Stuff& other){
if(this != &other){
this->name = other.name;
}
}
std::string Stuff::getName(){
return name;//exc_bad_access triggered here
}

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

void methodA(){
Stuff localStuff;
myClassInstance.addToStuffList("mostrecentstuff",localStuff);
}
...
void methodB(){
//different method now, localStuff would be out of scope but
//shouldn't matter since we passed by value in addToStuffList, right?
Stuff* pStuff = myStuffListIndex["mostrecentstuff"];
std::cout << "Hello, my name is " << pStuff->getName() << std::endl;
}

int main(int argc, const char* argv[]){
methodA();
methodB();
}

Почему доступ pStuff-> getName () выбрасывает exc_bad_access?

0

Решение

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

Вы никогда не должны хранить указатели на элементы в контейнерах std, но для векторов вы можете сохранить их индексы.

Вам придется :

std::vector<Stuff> myStuffList;
std::tr1::unordered_map<std::string,int> myStuffListIndex;

а также

myStuffList.push_back(ability);//our man is guaranteed to be at tail
myStuffListIndex[name] = myStuffList.size() - 1;//store

Если ваше приложение является многопоточным, вам придется защищать приведенный выше код мьютексом

1

Другие решения

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

Таким образом, ваш дизайн поврежден (вам нужно будет обновлять карту при каждом изменении размера вектора).

Затем, что касается вашего теста, так как вы выполняете только одну вставку, указатель на элемент вектора по-прежнему действителен. Но, глядя на ваш addToStuffList() метод, я вижу:

void MyClass::addToStuffList(std::string name, Stuff stuff){
myStuffList.push_back(ability);//our man is guaranteed to be at tail
myStuffListIndex[name] = &myStuffList[myStuffList.size()-1];//store
//pointer to object that we just copy-constructed at tail of list
}

Не должно ли это быть:

myStuffList.push_back(stuff);

Что такое ability?

1

По вопросам рекламы [email protected]