Не понимать ошибку во время сериализации gSOAP - PullRequest
0 голосов
/ 10 февраля 2012

Работа с 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 Ответ

0 голосов
/ 10 февраля 2012

Вы всегда должны использовать 'new' вместо '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 экземпляра не инициализирован, поэтому динамический вызов метода приводит к сбою.

...