带有C+的AccessViolationException+/CLI和本机互操作 我有一个CLI/C++类实例化一个本地C++对象,然后在那个对象上调用一个方法,并返回一些数据。我收到了随机的AccessViolationExceptions,无法了解发生了什么。以下是我的代码的精简版本: public ref class MyWrapper { public: MyWrapper() { nativeObject = new NativeObject(); } Object^ getData(String^ field) { string nativeField = msclr::interop::marshal_as<string>(field); Data nativeResult = nativeObject->getData(nativeField); Object^ result = convertToManaged(nativeResult); return result; } Object& convertToManaged(Data data) { // This converts the char* noted below back into its basic data type, and returns it as an object } private: NativeObject* nativeObject; }
数据的粗略定义:带有C+的AccessViolationException+/CLI和本机互操作 我有一个CLI/C++类实例化一个本地C++对象,然后在那个对象上调用一个方法,并返回一些数据。我收到了随机的AccessViolationExceptions,无法了解发生了什么。以下是我的代码的精简版本: public ref class MyWrapper { public: MyWrapper() { nativeObject = new NativeObject(); } Object^ getData(String^ field) { string nativeField = msclr::interop::marshal_as<string>(field); Data nativeResult = nativeObject->getData(nativeField); Object^ result = convertToManaged(nativeResult); return result; } Object& convertToManaged(Data data) { // This converts the char* noted below back into its basic data type, and returns it as an object } private: NativeObject* nativeObject; },c++,c++-cli,C++,C++ Cli,数据的粗略定义: class Data { private: string field; int dataType; char* dataArray; size_t size; public: Data() { dataArray = NULL; } Data(const Data &value) { copyData(value); } ~Data() { delete d
class Data
{
private:
string field;
int dataType;
char* dataArray;
size_t size;
public:
Data()
{
dataArray = NULL;
}
Data(const Data &value)
{
copyData(value);
}
~Data()
{
delete dataArray;
}
void copyData(const Data &value)
{
dataType = value.dataType;
size = value.size;
if (value.dataArray != NULL)
{
dataArray = new char[value.size];
memcpy(dataArray, value.dataArray, value.size);
}
else
{
dataArray = NULL;
}
}
Data& Data::operator=(const Data & value)
{
copyData(value);
return *this;
}
void addData()
{
/* This converts a basic data type like a double into a char* with reinterpret_cast,
like this:
double* newValue = new double();
*newValue = value;
dataArray = reinterpret_cast<char*>(newValue);
size = sizeof(double);
*/
}
}
类数据
{
私人:
字符串字段;
int数据类型;
字符*数据数组;
大小;
公众:
数据()
{
dataArray=NULL;
}
数据(常量数据和值)
{
复制数据(值);
}
~Data()
{
删除数据数组;
}
无效复制数据(常量数据和值)
{
数据类型=value.dataType;
大小=value.size;
if(value.dataArray!=NULL)
{
dataArray=新字符[value.size];
memcpy(dataArray,value.dataArray,value.size);
}
其他的
{
dataArray=NULL;
}
}
数据和数据::运算符=(常量数据和值)
{
复制数据(值);
归还*这个;
}
void addData()
{
/*这会将double之类的基本数据类型转换为具有reinterpret_cast的char*,
这样地:
double*newValue=newdouble();
*newValue=值;
dataArray=reinterpret\u cast(newValue);
尺寸=sizeof(双倍);
*/
}
}
大多数情况下,这种方法很好用。我有一个C#测试程序集,它使用各种(预期的)输入类型运行它,并且运行时没有问题。但是,当我把它放在一个更大的应用程序上下文中时,它会随机抛出AccessViolationExceptions。虽然它们中的大多数都来自这段代码本身,但并不总是在同一个地方——有时是托管getData函数,有时是本机getData函数。更奇怪的是,当使用此代码运行时,应用程序中纯管理的随机其他部分将给我AccessViolationException,这在添加此代码之前从未发生过
知道发生了什么事吗?很明显,我的记忆力有问题,但我不知道是什么。我尝试了一些变化(将本机数据对象作为指针返回,从托管代码中创建结果对象作为pin_ptr,并将其作为参数传递,等等),但它们都会产生类似的结果
注释掉result.addData()似乎可以消除这个问题。该方法所做的只是分配一些存储在dataArray字段中的内存。然后将其传递回托管代码这一事实可能是问题所在吗?您为
数据
类提供的复制构造函数为空,因此,无论何时进行复制,您都在创建一个对象,而不是要复制的对象的副本。发生的情况是,您的程序现在正在传递未完成的副本,而没有dataArray
元素集
这些错误(用户定义的复制构造函数已损坏或不完整)是最难诊断的错误之一。必须完成代码,复制构造函数才能执行真正的复制
此外,您还需要一个赋值运算符来完成“规则3”
编辑:正确编码的副本构造函数示例如下:
Data(const Data &value) : field(value.field), dataType(value.dataType), dataArray(0)
{
addData(dataType, value.dataArray);
}
并在addData
中确定数据类型
其他信息:
析构函数不需要检查NULL,因为它不是必需的
~Data()
{
delete dataArray;
}
此外,赋值运算符将如下所示:
#include <algorithm>
//...
Data& operator=(Data value)
{
std::swap(value.dataType, dataType);
std::swap(value.dataArray, datArraye);
std::swap(value.field, field);
return *this;
}
#包括
//...
数据和运算符=(数据值)
{
std::swap(value.dataType,dataType);
std::swap(value.dataArray,datArraye);
标准::交换(value.field,field);
归还*这个;
}
Google“c++三规则”,您使用dataArray成员违反了该规则。函数的作用是致命的。可能不是唯一的地方。你是说我缺少复制构造函数和析构函数吗?我确实有这些-对不起,应该包括它们。@Deeko-规则3也需要赋值运算符。第二,你的复制构造函数是假的。它什么也不做,也不复制。这种虚假性足以导致像你这样的复制程序出现问题。你能解释一下是什么导致它是虚假的吗?我将其转换回值类型,为新对象创建一个新指针,然后将该值放入该指针中。“少了一步吗?”@Deeko-见下面我的答案。您的复制构造函数的责任是复制。你的代码拒绝这样做。它不是空的。注释掉的部分解释了它的功能。我可以把所有的东西都填好,但那没用。数据类在不同的数据类型上运行,并根据特定的输入,将dataArray转换为不同的原语。在这里输入所有内容并不会增加问题的内容,所以我举了一个例子,说明它对双打的作用。@Deeko-请编辑您的问题。当你发布代码时,我们要做的就是你发布的内容。如果我们没有看到实现,那么就没有实现。是的,你发布它是很重要的,因为你的代码调用了复制构造函数。很抱歉不清楚-我确实在复制构造函数中发布了代码,但是在一个注释中,因为不是每种情况都完整。我对原始问题进行了编辑以反映这一点,但是,正如新的评论所说,“else”案例实际上填写了dataArray,就像它填写double的方式一样,只是填写了其他数据类型。@Deeko-复制构造函数的唯一职责是创建一个副本。我不能再强调这个了。您的实现充其量是不可靠的。您根本不应该执行任何if语句——只需获取传递给您的对象,并创建它的精确副本。如果你不这样做,那么我的答案是——你可能会传递一些半生不熟的副本。你用新的代码更新了你的问题。您的赋值运算符现在有故障。请使用我在上面的答案中发布的答案。或者更好的方法是使用std::vector
,这样就不需要assig了
#include <algorithm>
//...
Data& operator=(Data value)
{
std::swap(value.dataType, dataType);
std::swap(value.dataArray, datArraye);
std::swap(value.field, field);
return *this;
}