Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 与本地静态std::map的访问冲突<;标准::字符串,标准::弱\u ptr>;内部成员函数(C+;+;11/STL)_C++_C++11 - Fatal编程技术网

C++ 与本地静态std::map的访问冲突<;标准::字符串,标准::弱\u ptr>;内部成员函数(C+;+;11/STL)

C++ 与本地静态std::map的访问冲突<;标准::字符串,标准::弱\u ptr>;内部成员函数(C+;+;11/STL),c++,c++11,C++,C++11,我的问题有点复杂,但我尽量简单地描述它。 我想在我的一个类中用一个本地静态成员(类型为std::map)实现一个静态方法。每次调用此方法时,它都应该查找映射中是否有以传递的参数为键的对象。该方法返回的值是std::shared_ptr(如果可以锁定std::弱_ptr,则根据映射中的std::弱_ptr构造,否则将构造一个新的std::shared_ptr,并将其作为std::弱_ptr添加到std::map)。但我在调用std::map.find()的线路上“有时”会收到访问冲突 “有时”的意

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

“有时”的意思是:如果一个
std::weak_ptr
被添加到映射中,然后由于无法锁定而被删除-并构建一个新的
std::shared_ptr
,作为
std::weak_ptr
添加到
std::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;
}
#包括
#包括
#包括
#包括
类MyClass{
公众:
MyClass(INTA){
这->a=a;
}
虚拟~MyClass(){}
私人:
INTA;
};
类MyStaticClass{
公众:
静态std::shared_ptr myMethod(const char*string){
静态std::map;
std::shared_ptr retVal=nullptr;
std::map::iterator iter=map.find(std::string(string));
if(iter!=map.end()){
retVal=iter->second.lock();
如果(!retVal){
/*ptr已经消失,所以请将其从地图中删除*/
iter=映射擦除(iter);
}
}
如果(!retVal){
/*未在地图中找到或已擦除-需要重新创建*/
retVal=std::使_共享(atoi(字符串));
std::弱ptr weakRetVal=retVal;
插入(std::make_pair(std::string(string),weakRetVal));
}
返回std::移动(retVal);
}
};
int main(int argc,char*argv[]){
{
std::sharedptrmyintpointer=MyStaticClass::myMethod(“1”);
}
{
std::sharedptrmyintpointer=MyStaticClass::myMethod(“1”);
}
{
std::sharedptrmyintpointer=MyStaticClass::myMethod(“1”);
}
返回0;
}
编译器/平台:VS 2012/Windows 8

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


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

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

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

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

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

unsigned char keyValues[sizeof(unsigned short)];

当然,
sizeof()
运算符不会返回类型的最大值,而是返回以字节为单位的大小(即x86和x64上为2,或者在某些情况下,由于对齐,返回4)。因此,如果我将sizeof(unsigned short)替换为65536(或
中的
USHRT\u MAX
),我的代码将在没有任何访问权限的情况下正常运行…:(愚蠢的错误会带来致命的后果…

第一段让我想起。“但我目前无法在这里重现访问冲突。”您的原始代码是否使用来自多个线程的
myMethod
(以非顺序方式)?@DyP不,它只是从主线程调用的,您不应该移动返回值
std::move(retVal);
。它禁止NRVO。@DyP哦,我明白了-谢谢你指出这一点!但是访问权限违反了