简体   繁体   English

使用本地静态std :: map的访问冲突 <std::string, std::weak_ptr> 在成员函数中(C ++ 11 / STL)

[英]Access Violation with local static std::map<std::string, std::weak_ptr> in member function (C++11/STL)

My Problem is somehow complicated, but I try to describe it simply. 我的问题某种程度上很复杂,但是我尝试简单地描述一下。 I want to implement an static method in one of my classes with an local static member (of type std::map<std::string, std::weak_ptr> ). 我想在一个类中使用本地静态成员(类型为std::map<std::string, std::weak_ptr> )实现一个静态方法。 Every time this method is called, it should look up if theres an object in the map with the passed argument as key. 每次调用此方法时,都应查找映射中是否存在以传递的参数作为键的对象。 The value that is returned by the method is an std::shared_ptr (constructed from the std::weak_ptr in the map, if the std::weak_ptr can be locked - otherwise an new std::shared_ptr is constructed and added as std::weak_ptr to the std::map ). 该方法返回的值是std::shared_ptr (如果可以锁定std::weak_ptr ,则从地图中的std::weak_ptr构造-否则,将构造新的std::shared_ptr并将其添加为std::weak_ptrstd::map )。 But I receive 'sometimes' an access violation on the line where I call std::map.find() . 但是我有时在调用std::map.find()的行上收到访问冲突。

'Sometimes' means: If one std::weak_ptr is added to the map, then erased because it couldn't be locked - and an new std::shared_ptr is constructed, added as std::weak_ptr to the std::map . “有时”的意思是:如果将一个std::weak_ptr添加到地图,则由于无法锁定而将其删除-并构造了一个新的std::shared_ptr ,并将其作为std::weak_ptr添加到std::map The next time my static method try to look up inside the std::map there MIGHT BE (occasionally) an Access Violation coming from: 下次我的静态方法尝试在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();'

I can't find any way then to debug the problem better - any help here is greatly appreciated. 我找不到任何更好的方法来调试问题-非常感谢这里的任何帮助。

Last but not least some code I rewrited to have an short, self-explaining example. 最后但并非最不重要的一点是,我重写了一些简短的自我解释示例。 But I couldn't reproduce an access violation here so far. 但到目前为止,我无法重现访问冲突。

#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;
}

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

Edit: I found out so far, that the size of 'map' is always 0 again (at least according to the debugger), when this fault happens. 编辑:到目前为止,我发现,当发生此错误时,“ map”的大小始终再次为0(至少根据调试器而言)。 So ie I start the program with map uninitalized (size is 0 of course). 因此,即我以未初始化的地图(当然大小为0)启动程序。 Then entrys are added using myMethod() - the size of the map is ie 4. Now the std::weak_ptr expires and I make again calls to myMethod(). 然后使用myMethod()添加条目-映射的大小为4。现在std :: weak_ptr到期,我再次调用myMethod()。 The debugger shows now map.size() would be 0 again (map entrys are never removed, so this shouldn't be possible). 调试器现在显示map.size()再次为0(永远不会删除映射条目,因此这是不可能的)。

Edit2: When the size should be 0x00000004 there is also the case, that the debugger shows 0xff000004 as size (and of course most 'entries' can't be displayed then). Edit2:当大小应为0x00000004时,还有一种情况是,调试器将大小显示为0xff000004(当然,大多数“条目”然后无法显示)。 Could there be any 32bit/64bit issue involved with local static storage? 本地静态存储是否可能涉及任何32bit / 64bit问题?

I found the soulution for my problem like suggested by the comments in an stack/heap corruption from a different piece of code. 我找到了解决问题的方法,就像来自另一段代码的堆栈/堆损坏中的注释所建议的那样。 Just in case someone with a similiar problem will find this question one day, I will briefly describe what were going wrong exactly and my steps to found the cause out. 万一某个有类似问题的人有一天会找到这个问题,我将简要地描述到底出了什么问题以及我找出问题的步骤。

1.) Because I didn't faced that problem when using an plain global function and an global static std::map it indicates that there were a problem in an similiar storage scope (local function static). 1.)因为使用普通的全局函数和全局静态std :: map时没有遇到该问题,所以它表明相似的存储范围(本地函数静态)中存在问题。 The reason why that access violation didn't happened for me when using an global static std::map was simply, that my stack/heap corruption taked place with an different local function static object in a different class. 使用全局静态std :: map时没有发生访问冲突的原因很简单,我的堆栈/堆损坏发生在另一个类中的另一个本地函数静态对象中。 So side effects to objects in the same storage scope are more likely than side effects with different storage scopes (ie local function static VS global static). 因此,与具有不同存储范围的副作用(即局部函数静态VS全局静态)相比,相同存储范围内的对象更有可能产生副作用。

2.) I just executed my code plenty of times to recognize a pattern when exactly the access violation happens and what my steps are to reproduce that behaviour. 2.)我刚执行了很多次代码,以识别出何时发生访问冲突的确切模式以及如何重现该行为的步骤。 Then I noticed, that my access violations happened with increased regularity if I was pressing an key on the keyboard. 然后我发现,如果我按键盘上的某个键,访问冲突就会越来越频繁地发生。 That seemed already like an very strange side effect to me and made me check specially my input classes. 对我来说,这似乎已经是一个非常奇怪的副作用,并让我特别检查了我的输入类。

3.) There I found the fatal piece of code: I used the singleton approach for one of my input classes (which means: the class got an static getInstance() method which returns an local function static object of the class itself). 3)在那找到了致命的代码:我对我的一个输入类使用了单例方法(这意味着:该类有一个静态的getInstance()方法,该方法返回该类本身的局部函数静态对象)。 As a reminder: My access violation also happened with an local function static object. 提醒一下:我的访问冲突也发生在本地函数静态对象上。 Very suspiciously... Looking deeper through this class, I found an member to store the actual key values in an array. 非常可疑...通过深入研究此类,我找到了一个将实际键值存储在数组中的成员。 The array size was declared with the use of some obscure macros which resolved simplified to something like: 数组大小是通过使用一些晦涩的宏声明的,这些宏简化为以下形式:

unsigned char keyValues[sizeof(unsigned short)];

But of course the sizeof() operator doesn't return the maximum value of an type - but rather the size in Bytes (ie 2 on x86 & x64 - or in some cases 4 because of alignment). 但是,当然, sizeof()运算符不会返回类型的最大值-而是以字节为单位的大小(即x86和x64上为2-或在某些情况下为4,这是因为对齐)。 So if I replaced sizeof(unsigned short) by 65536 (or USHRT_MAX from <climits> ) my code runs clenaly without any access violtion... :( Stupid mistake with fatal consequences... 因此,如果我用65536(或<climits> USHRT_MAX )替换了sizeof(unsigned short),我的代码运行得很顺畅,没有任何访问冲突... :(愚蠢的错误导致致命的后果...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM