C#& C ++:“试图读取或写入受保护的内存”错误

时间:2009-11-29 13:01:36

标签: c# c++ visual-c++

以下代码编译没有错误。基本上,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);
}

4 个答案:

答案 0 :(得分:1)

_it中的成员StdStringContainer从未初始化为指向_items向量。这意味着它是一个无效的迭代器。当您在_it中将it分配给GetNext()时,您已it提供_it中存在的无效,未初始化的值。然后通过_it递增未初始化的_it++,这就是触发你的错误。

正如Stroustrup在19.2中所说,未初始化的迭代器是一个无效的迭代器。这意味着您的未初始化_it无效,并且使用它执行的操作未定义,可能会导致严重失败。

然而,你的问题更深层次。迭代器与它们枚举的容器的生命周期根本不同。除非容器是不可变的并且在构造函数中初始化,否则实际上没有任何“好”方法可以用这样的迭代器成员执行。

如果你不能公开std :: namespace名称,你是否考虑过通过typedef对它们进行别名,例如?您的组织或项目怎么样才能公开模板类?

答案 1 :(得分:0)

听起来你有内存泄漏。我建议寻找有指针算术,写入内存或数组使用的任何地方。检查数组访问中的边界条件。

另一个问题:泄漏许多甚至不在您的代码中。如果是这种情况,您将不得不从项目中排除库。

答案 2 :(得分:0)

从我的角度来看,主要问题是您在iterator课程中将vector存储到stdStringContainer。请记住,每当向量调整大小时,所有现有的迭代器都将失效。因此,每当您向向量中插入操作时,它可能会调整大小并且您的现有迭代器变为无效。如果您尝试在GetNext()中取消引用它,那么它将访问无效的内存位置。为了检查是否真的如此,尝试将初始向量大小保留为某个相对较大的数字,以便不会发生调整大小。您可以使用reserve()方法保留大小,在这种情况下,可以保证向量的capacity()大于或等于保留值。

答案 3 :(得分:0)

我的猜测是,你遇到了崩溃,因为两个C ++模块之间的接口中的std::stringstd::vector是用不同的编译器和运行时库编译的。

矢量和字符串的内存布局可能会在VC6和2005之间发生变化。

当2005 DLL分配类型为StdStringContainerStdStringWrapper的对象时,它会根据2005标题中stringvector的声明进行分配。

当在这些对象(使用VC6编译器和库编译)上调用成员函数时,它们会采用不同的内存布局,并且会因访问冲突而失败。