gsoap выделяет mem для динамического массива структур. - PullRequest
0 голосов
/ 12 сентября 2018

gSoap с пользой создает заглушки для управления памятью и т. Д. Одной из этих команд является soap_malloc, но, похоже, нет соответствующего soap_realloc.Прежде чем я начну писать свои собственные методы push и pop, я просто хочу убедиться, что я ничего не упустил.

//example.h generated with wsdl2h

struct ns1___Customer
{
    int   __sizeProduct;     
    ns1__Product *Product;        
    int  customerid;       
}

struct ns1__Product
{
    int  productid;
}

В настоящее время я использую soap_malloc, а затем realloc для динамического увеличения массива.

//I could use soap_new_ns1__Product(&soap,XXX) and allocate mem for XXX
//number of ns1__Product structures but this is wasteful and doesn't solve 
//anything

struct ns1__Customter cust;
soap_default_ns1__Product(soap, &cust);

struct ns1__Product *prod_array = NULL;

//allocate mem for 1 product
prod_array = soap_new_ns1__Product(soap,1) ;

soap_default_ns1__Product(soap, &prod_array[0]);
prod_array[0].productid=111;

//Need to add product therefore need to realloc mem. 
//IS THIS THE BEST WAY IN gsoap?
prod_array = realloc( prod_array, 2 * sizeof(struct  ns1__Product)) ;
soap_default_ns1__Product(soap, &emp_array[1]);
prod_array[1].product=222;

//assigning array ptr to Customer
cust.Product=prod_array;
// Remember to adjust sizeProduct
cust.__sizeProduct=2;

Это кажется неправильным и неуклюжим, предлагает ли gsoap лучший способ?Я не могу найти четкого примера в документации или при поиске в Интернете.

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

То, что вы там делаете, действительно неверно.После использования soap_new_T() (где T в вашем случае - ns1__Product), контекст soap теперь управляет этой памятью, удерживая указатель ns1__Product* внутри.Позже, когда вы вызовете soap_destroy(), чтобы освободить все soap_new_T() выделенные объекты, управляемые контекстом soap, контекст будет пытаться освободить указатель, который больше не указывает на действительную память, так как вы вызвалиrealloc().

Как отметил Джон Боллинджер , в gSOAP нет встроенного способа сделать что-то похожее на realloc.Вместо этого вам просто нужно сделать перераспределение вручную, например:

// allocate memory for 1 product (as you already do above)
prod_array = soap_new_ns1__Product(soap, 1);

// ... do some stuff, realize you need to "realloc" to add another product ...

// allocate a new array, managed by the soap context
struct ns1__Product* new_array = soap_new_ns1__Product(soap, 2);

// copy the old array into the new one (assuming old_size is however many elements are in prod_array)
for(std::size_t i = 0; i < old_size; ++i)
{
    new_array[i] = prod_array[i];
}

// tell the soap context to destroy the old array
soap_dealloc(soap, prod_array);

В стороне:

Кажется, что можно использовать std::vector<ns1__Product> вместомассив, который решит вашу проблему возможно лучшим способом, но этот вопрос уже задавался здесь безрезультатно.К сожалению, в настоящее время я не знаю ответа на этот вопрос.

0 голосов
/ 12 сентября 2018

Прежде чем я начну писать свои собственные методы push и pop, я просто хочу убедиться, что я не пропускаю ничего очевидного.

Я подозреваю, что вам не хватает, что soap_malloc() выделяет память , которая автоматически освобождается по крайней мере при некоторых обстоятельствах.Таким образом, использование realloc() для изменения размера выделенной памяти вызывает проблемы.Существует реальная вероятность того, что перераспределение как таковое будет успешным, но вы, вероятно, как минимум, получите неприятный беспорядок, когда автоматическое освобождение gSOAP попытается вмешаться в soap_end().

С другой стороны,Я не думаю, что вы пропускаете какую-либо функцию перераспределения. Документы действительно, похоже, не описывают ничего.Вы всегда можете реализовать свою собственную оболочку перераспределения, которая выделяет свежую память с помощью soap_malloc(), копирует содержимое исходного пространства (размер которого вам нужно каким-либо образом узнать) и освобождает исходное пространство с помощью soap_dealloc().

Суть в том, что soap_malloc() не предназначен для использования в качестве распределителя общего назначения, и он не особенно подходит для вашего варианта использования.Его основная задача, по-видимому, внутренняя, чтобы избавить пользователей библиотеки от необходимости вручную освобождать временные объекты, которые выделяет библиотека.Я полагаю, что это удобно для пользователей библиотеки для их непосредственного использования.

Если вы хотите иметь возможность перераспределять блоки, то я предлагаю вам сначала получить их с помощью обычного malloc().Вам нужно внимательно прочитать документы, если вы собираетесь смешивать malloc() отредактированные данные с soap_malloc() отредактированными данными, но это, вероятно, возможно.В качестве альтернативы рассмотрите подходы, которые не требуют перераспределения, например, хранение данных в связанном списке вместо динамического массива.

...