Не понимать ошибку во время сериализации gSOAP
Работа с gSoap 2.7.17 на Windows, C# и управляемом C++.
У меня есть (gSOAP) классы, описывающие массив файлов:
class ns__ContainerFile
{
public:
xsd__long fileId;
xsd__string fileName;
};
class ContainerFileArray
{
public:
ns__ContainerFile *__ptr;
int __size;
};
class ns__Container
{
public:
xsd__long containerId 0:1 = 0;
xsd__string name 0:1 = "";
xsd__string description 0:1 = "";
ContainerFileArray* files 0:1 = NULL;
};
В управляемом C++ я выделяю свой возвращаемый массив:
ContainerFileArray gSoapArray;
gSoapArray.__size = managedArray->Length;
gSoapArray.__ptr = (ns__ContainerFile*) soap_malloc(soap, sizeof(ns__ContainerFile) * gSoapArray.__size);
Приведенный выше код является частью метода с именем ConvertArray, который вызывается так:
ns__Container unManaged;
*unManaged.files = ConvertArray(soap, managed->files->ToArray());
Проблема в том, что, хотя ConvertArray, кажется, работает должным образом (я вижу элементы данных, по-видимому, должным образом заполненные в памяти malloc), я получаю нарушения доступа на этапе сериализации, когда мы завершим запрос веб-службы (т.е.: наш код C++ выдал возвращаемое значение SOAP_OK, и логика вернулась к автоматически сгенерированному коду gSOAP).
Весь этот процесс работает очень хорошо, когда имеешь дело с массивами простых типов - целыми, длинными и т. Д., Но взрывается с более сложными типами - классами и тому подобным.
Если в методе ConvertArray я подставлю в строку 3:
gSoapArray.__ptr = soap_new_ns__ContainerFile(soap, gSoapArray.__size);
выделить память, все отлично работает.
Так что я не уверен, что понимаю почему. В первом случае я использую soap_malloc для выделения блока памяти, размер которого соответствует размеру класса ContainerFile, однако многие элементы находятся в управляемом массиве. Во втором случае все сводится к использованию soap_new для того же. Если выделенная память полностью управляется gsoap и в остальном одинакова (насколько я могу судить), почему отказывает версия с soap_malloc во время сериализации?
Используя Visual Studio, я вижу, что он не работает в следующем сгенерированном коде:
void ContainerFileArray::soap_serialize(struct soap *soap) const
{
if (this->__ptr && !soap_array_reference(soap, this, (struct soap_array*)&this->__ptr, 1, SOAP_TYPE_ContainerFileArray))
for (int i = 0; i < this->__size; i++)
{ soap_embedded(soap, this->__ptr + i, SOAP_TYPE_IDCXDService__ContainerFile);
this->__ptr[i].soap_serialize(soap);
}
}
Индикатор находится на выделенной линии, но я подозреваю, что он не удался в вызове soap_embedded. Я также должен отметить, что он не работает на первом элементе в блоке malloc (то есть: когда i == 0).
1 ответ
Вы всегда должны использовать "новый" вместо "malloc" в C++, как в:
gSoapArray.__ptr = soap_new_ ns__ContainerFile(soap, gSoapArray.__size);
Или, что еще лучше, используйте STL std::vector в заголовочном файле gSOAP следующим образом:
#import "stlvector.h"
class ns__Container
{
public:
xsd__long containerId 0:1 = 0;
xsd__string name 0:1 = "";
xsd__string description 0:1 = "";
std::vector<ns__ContainerFile> files 0:1 = NULL;
};
По сути, malloc небезопасен в C++, поскольку VMT экземпляра не инициализируется, поэтому динамический вызов метода приводит к сбою.