c++ - 成员函数中局部静态 std::map<std::string, std::weak_ptr> 的访问冲突 (C++11/STL)

标签 c++ c++11

我的问题有点复杂,但我尝试简单地描述它。 我想在我的一个类中使用本地静态成员(类型为 std::map<std::string, std::weak_ptr> )实现静态方法。每次调用此方法时,它都应该查找映射中是否存在以传递的参数作为键的对象。该方法返回的值是 std::shared_ptr (如果 std::weak_ptr 可以被锁定,则从 map 中的 std::weak_ptr 构建 - 否则构建新的 std::shared_ptr 并将其作为 std::weak_ptr 添加到 std::map )。但我“有时”在调用 std::map.find() 的线路上收到访问冲突。 .

“有时”的意思是:如果有的话std::weak_ptr被添加到 map 中,然后因为无法锁定而被删除 - 以及一个新的 std::shared_ptr已构建,添加为 std::weak_ptrstd::map 。 下次我的静态方法尝试在 std::map 内部查找时可能(偶尔)出现访问冲突来自:

File: Microsoft Visual Studio 11.0\VC\include\xtree
Line: 2092
Method: _Nodeptr _Lbound(const key_type& _Keyval)
Access Violation at reading: '_Nodeptr _Pnode = _Root();'

我找不到任何方法来更好地调试问题 - 非常感谢这里的任何帮助。

最后但并非最不重要的一点是,我重写了一些代码,以获得一个简短的、不言自明的示例。但到目前为止,我无法在这里重现访问冲突。

#include <map>
#include <memory>
#include <string>
#include <iostream>

class MyClass{
public:
  MyClass(int a){
    this->a = a;
  }
  virtual ~MyClass(){ }
private:
int a;
};

class MyStaticClass{
public:
  static std::shared_ptr<MyClass> myMethod(const char* string){
    static std::map<std::string, std::weak_ptr<MyClass>> map;
    std::shared_ptr<MyClass> retVal = nullptr;
    std::map<std::string, std::weak_ptr<MyClass>>::iterator iter = map.find(std::string(string));

    if(iter != map.end()){
      retVal = iter->second.lock();
      if(!retVal){
        /* ptr is gone already, so remove it from map */
        iter = map.erase(iter);
      }
    }
    if(!retVal){
      /* not found in map OR erased - need to be created again */
      retVal = std::make_shared<MyClass>(atoi(string));
      std::weak_ptr<MyClass> weakRetVal = retVal;
      map.insert(std::make_pair(std::string(string), weakRetVal));
    }
    return std::move(retVal);
  }
};

int main(int argc, char* argv[]){
  {
    std::shared_ptr<MyClass> myIntPointer = MyStaticClass::myMethod("1");
  }
  {
    std::shared_ptr<MyClass> myIntPointer = MyStaticClass::myMethod("1");
  }
  {
    std::shared_ptr<MyClass> myIntPointer = MyStaticClass::myMethod("1");
  }
  return 0;
}

编译器/平台:VS 2012/Windows 8

编辑:到目前为止,我发现,当发生此错误时,“map”的大小始终再次为 0(至少根据调试器)。也就是说,我以未初始化的 map 启动程序(当然大小为 0)。然后使用 myMethod() 添加条目 - 映射的大小为 4。现在 std::weak_ptr 过期,我再次调用 myMethod()。调试器现在显示 map.size() 将再次为 0(映射条目永远不会被删除,因此这应该是不可能的)。

Edit2: 当大小应该为 0x00000004 时,调试器也会显示 0xff000004 作为大小(当然,大多数“条目”此时无法显示)。本地静态存储是否存在 32 位/64 位问题?

最佳答案

我找到了问题的解决方案,就像另一段代码的堆栈/堆损坏中的注释所建议的那样。以防万一有类似问题的人有一天会发现这个问题,我将简要描述到底出了什么问题以及我找出原因的步骤。

1.) 因为我在使用普通全局函数和全局静态 std::map 时没有遇到这个问题,所以它表明在类似的存储范围(本地函数静态)中存在问题。使用全局静态 std::map 时没有发生访问冲突的原因很简单,我的堆栈/堆损坏发生在不同类中的不同本地函数静态对象上。因此,对同一存储范围内的对象产生副作用的可能性比对不同存储范围的对象产生副作用的可能性更大(即局部函数静态 VS 全局静态)。

2.) 我刚刚执行了多次代码,以识别访问冲突何时发生的模式以及重现该行为的步骤。然后我注意到,如果我按下键盘上的某个键,我的访问违规发生的频率就会增加。这对我来说似乎已经是一个非常奇怪的副作用,并让我特别检查我的输入类。

3.) 在那里我发现了致命的一段代码: 我对我的一个输入类使用了单例方法(这意味着:该类有一个静态 getInstance() 方法,该方法返回该类本身的本地函数静态对象)。提醒一下:我的访问冲突也发生在本地函数静态对象上。非常可疑...通过这个类进行更深入的研究,我发现一个成员将实际的键值存储在数组中。数组大小是使用一些晦涩的宏来声明的,这些宏被简化为:

unsigned char keyValues[sizeof(unsigned short)];

当然是sizeof()运算符不返回类型的最大值 - 而是返回以字节为单位的大小(即 x86 和 x64 上为 2 - 或在某些情况下由于对齐而为 4)。因此,如果我用 65536 (或 USHRT_MAX 中的 <climits> )替换 sizeof(unsigned Short) ,我的代码可以干净地运行,没有任何访问冲突... :( 愚蠢的错误会带来致命的后果...

关于c++ - 成员函数中局部静态 std::map<std::string, std::weak_ptr> 的访问冲突 (C++11/STL),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19069948/

相关文章:

c++ - SDL_RenderCopy() 意外行为

c++ - 生成模板包

c++ - 在这种情况下,为什么 std::bind 中需要占位符?

c++ - 在 C++ 中存储对对象的引用需要多少内存?

c++ - 为什么 std::is_array 对 std::array 返回 false?

c++ - 模板函数的歧义递归定义

c++ - 用一个循环遍历二维数组

c++ - 有没有办法在Windows下编译为Linux编写的C++代码?

c++ - 如何在大型 xml 文件中获取正确的数据?

c++ - 如何通过非类型参数选择特化