C# & C++:“试图读取或写入受保护的内存”错误
Posted
技术标签:
【中文标题】C# & C++:“试图读取或写入受保护的内存”错误【英文标题】:C# & C++: "Attempted to read or write protected memory" Error 【发布时间】:2009-11-29 13:01:36 【问题描述】:以下代码编译没有错误。基本上,C#2005 控制台应用程序调用 VC++2005 类库,后者又调用本机 VC++6 代码。运行 C#2005 应用程序时出现以下错误:
“未处理的异常:System.AccessViolationException:试图读取或写入受保护的内存。这通常表明其他内存已损坏。”
这个错误的原因是什么?以及如何去纠正它?
Edit1:它在 StdStringWrapper ssw = w.GetNext();
行崩溃Edit2:我听从了 Naveen 的建议,使用整数索引而不是迭代器,现在没有更多错误了。非常感谢所有发表评论的人!
用 C#2005 编写的代码作为控制台应用程序:
class Program
static void Main(string[] args)
Class1 test= new Class1();
test.PerformAction();
test.PerformAction();
test.PerformAction();
test.PerformAction();
在 VC++2005 中作为类库编写的代码:
public ref class Class1
public:
void PerformAction();
;
void Class1::PerformAction()
DoSomethingClass d;
StdStringContainer w;
d.PerformAction(w);
for(int i=0; i<w.GetSize(); i++)
StdStringWrapper ssw = w.GetNext();
std::cout << ssw.CStr() << std::endl;
在 VC++6 中作为动态链接库编写的代码:
#ifdef NATIVECODE_EXPORTS
#define NATIVECODE_API __declspec(dllexport)
#else
#define NATIVECODE_API __declspec(dllimport)
#endif
class NATIVECODE_API StdStringWrapper
private:
std::string _s;
public:
StdStringWrapper();
StdStringWrapper(const char *s);
void Append(const char *s);
const char* CStr() const;
;
StdStringWrapper::StdStringWrapper()
StdStringWrapper::StdStringWrapper(const char *s)
_s.append(s);
void StdStringWrapper::Append(const char *s)
_s.append(s);
const char* StdStringWrapper::CStr() const
return _s.c_str();
//
class NATIVECODE_API StdStringContainer
private:
std::vector<StdStringWrapper> _items;
std::vector<StdStringWrapper>::iterator _it;
public:
void Add(const StdStringWrapper& item);
int GetSize() const;
StdStringWrapper& GetNext();
;
void StdStringContainer::Add(const StdStringWrapper &item)
_items.insert(_items.end(),item);
int StdStringContainer::GetSize() const
return _items.size();
StdStringWrapper& StdStringContainer::GetNext()
std::vector<StdStringWrapper>::iterator it = _it;
_it++;
return *it;
//
class NATIVECODE_API DoSomethingClass
public:
void PerformAction(StdStringContainer &s);
;
void DoSomethingClass::PerformAction(StdStringContainer &s)
StdStringWrapper w1;
w1.Append("This is string one");
s.Add(w1);
StdStringWrapper w2;
w2.Append("This is string two");
s.Add(w2);
【问题讨论】:
它在 StdStringContainer::GetNext() 中崩溃了吗? 是的,我检查了它,它在 StdStringContainer::GetNext() 处崩溃。知道为什么吗? 【参考方案1】:StdStringContainer
中的成员 _it
从未初始化为指向 _items
向量。这意味着它是一个无效的迭代器。当您在GetNext()
中将_it
分配给it
时,您已经给it
赋予了_it
中存在的无效、未初始化的值。然后,您通过_it++
增加未初始化的_it
,这就是触发您的错误的原因。
正如 Stroustrup 在 19.2 中所说,未初始化的迭代器是无效的迭代器。这意味着您未初始化的 _it
是无效的,并且使用它执行的操作是未定义的,并且可能会导致严重的失败。
但是,您的问题更深层次。迭代器的生命周期与其枚举的容器有着根本不同的生命周期。除非容器是不可变的并且在构造函数中初始化,否则实际上没有任何“好”的方法可以用这样的单个迭代器成员来做你想做的事情。
如果您不能公开 std:: 命名空间名称,您是否考虑过通过 typedef 给它们起别名,例如?您的组织或项目导致无法公开模板类的原因是什么?
【讨论】:
【参考方案2】:在我看来,主要问题是您在 stdStringContainer
类中将 iterator
存储到 vector
中。请记住,每当向量调整大小时,所有现有的迭代器都会失效。因此,每当您对向量进行插入操作时,它可能会调整大小并且您现有的迭代器变得无效。如果您尝试在GetNext()
中取消引用它,那么它将访问无效的内存位置。为了检查这是否真的是这种情况,请尝试将初始向量大小保留为某个相对较大的数字,以便不会发生调整大小。您可以使用reserve()
方法保留大小,这种情况下保证向量的capacity()
大于或等于保留值。
【讨论】:
我想出了 StdStringContainer 类,因为我需要使用 std::vector 并能够对其进行迭代。但是,我不能将 std::vector、std::string 等 STL 变量作为函数参数公开。我该如何纠正这个错误? 当向量重新分配时迭代器不会失效——指针会失效。这就是使用迭代器而不是向量上的指针的目标。从向量中删除元素时,迭代器可能会失效。 @KK:为什么不存储整数索引而不是迭代器? 区分重新分配(一个实现可以根据需要在内存中随机移动一个向量)和失效(当向量改变时发生)。 Sgi 的文档似乎没有做出同样的区分。具体来说,通过 Stroustrup (19.2):“迭代器可能无效......因为它 [未] 初始化,它指向一个已调整大小的容器,该容器已被销毁,或者它表示序列的结束。”没有关于迭代器失效的“重新分配”概念。 可以用整数索引访问std::vector中的项目吗?【参考方案3】:听起来你有内存泄漏。我建议查看有指针算术、写入内存或数组使用的任何地方。检查数组访问中的边界条件。
另一个问题:很多漏洞甚至不在您的代码中。如果是这种情况,您必须从项目中排除该库。
【讨论】:
【参考方案4】:我的猜测是,您有崩溃是因为两个 C++ 模块之间的接口中的 std::string
和 std::vector
是使用不同的编译器和运行时库编译的。
向量和字符串的内存布局在VC6和2005之间可能会发生变化。
当 2005 DLL 分配 StdStringContainer
和 StdStringWrapper
类型的对象时,它会根据 2005 标头中的 string
和 vector
声明进行分配。
当对这些对象(已使用 VC6 编译器和库编译)调用成员函数时,它们会采用不同的内存布局并因访问冲突而失败。
【讨论】:
以上是关于C# & C++:“试图读取或写入受保护的内存”错误的主要内容,如果未能解决你的问题,请参考以下文章
“试图读取或写入受保护的内存。这通常表明其他内存已损坏” DllImporting C#
c# emgu/opencv 使用抛出异常 - 试图读取或写入受保护的内存
Visual Studio C# 试图读取或写入受保护的内存。这通常表明其他内存已损坏
C 和 System.AccessViolationException 中的 allocVector():试图读取或写入受保护的内存?