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哦,我明白了-谢谢你指出这一点!但是访问权限违反了