C++ exc_bad_access 从 unordered_map 中指向的对象访问字符串字段

C++ exc_bad_access accessing string field from pointed-to object in 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?

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

正如 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 

如果您的应用程序是多线程的,则必须使用互斥锁来保护上述代码