2010-04-21 3 views
1

Я пишу функцию, которая берет строку, указатель строки и int. Функция разбивает строку на основе набора правил и помещает каждый токен в массив. Мне нужно вернуть массив из функции с количеством элементов в переменной int и т. Д. Я зациклен на том, как я возвращаю массив, поскольку я не могу использовать auto other wise, который он уничтожен, и я неохотно использую новые как Я чувствую, что это неоднородно.C++ Array проходящая дилемма

У меня есть другие идеи о том, как это сделать, но хотелось бы увидеть, как другие люди идут по этому поводу в первую очередь. Я также могу ошибаться, и можно было бы передать авто из массива. Я также не могу использовать векторы, поэтому идет конструктор копирования.

Векторный не может быть использован, так как это был вызов, заданный мне, и меня попросили не использовать шаблоны.

+0

Почему вы думаете, что вы не можете использовать векторы? – 2010-04-21 10:04:45

+0

Из любопытства, почему вы не можете использовать 'vector'? –

+0

Потому что это мой выбор не использовать вектор. – Thomas

ответ

2

Это больше вопрос C, чем вопрос на C++ с учетом этих ограничений.

Обычный шаблон C для возврата массива - это фактически заставить вызывающего передать в заполняемый массив. Это позволяет вызывающему принять решение о распределении (и, следовательно, освобождении).

Ваш прототип функции будет выглядеть

int Function(string str1, string_ptr str2, int n, int* pOutArray, int cOutArray); 

Если функция возвращает количество элементов написал pOutArray.

В реализации вы положили обработку для pOutArray, являющейся NULL, и в этом случае вы просто подсчитываете количество элементов и возвращаете это. Это позволяет вызвать функцию в одном из нескольких способов, в зависимости от ваших потребностей: -

int out[5]={0}; 
int cFilled = Function(s1,s2,x,out,_countof(out)); 
// Further code can use up to 5<cFilled elements from the array. 

или,

int cElt = Function(s1,s2,x,NULL,0); 
int* pOut = malloc(sizeof(int)*cElt); 
Function(s1,s2,x,pOut,cElt); 
// pOut now contains exactly the number of elements extracted. 
free(pOut); 
1

Естественным выбором будет, конечно, передать результат как std::vector<std::string>. Если вы не хотите использовать этот подход, существует два варианта:

  1. Позвольте клиенту кода обеспечить хранение результата, в этом случае было бы хорошей идеей, что клиент передает размер поставляемое хранилище.
  2. Выделите место для результата внутри с помощью new, я думаю, что это лучший, более надежный выбор. Вы, конечно же, должны удостовериться, что клиент позже удалит память с правильной версией delete или предоставит специальный механизм для освобождения памяти.
0

Если вы возвращаете массив фиксированного размера, вы можете использовать boost::array. Однако, если вы не хотите, чтобы добавить зависимость Boost, простое решение заключается в создании структуры данных с массива фиксированного размера, например:

 
template<typename T, std::size_t SIZE> 
struct array_wrapper 
{ 
    T array[SIZE]; 
}; 

Если размер можно изменить, а затем с помощью std::vector действительно действительно имеет смысл. Имейте в виду, что возврат класса оболочки (как указано выше) все равно приведет к созданию копии (хотя и компилятором). Таким образом, вы действительно не получаете каких-либо сбережений, передавая большой результат по значению, а не создавая его в куче и проходя вокруг указателей на выделенные данные, поэтому ваши требования не имеют смысла.

0

Передать в 'char & **' и 'int & *' параметры и выделить там жетоны, неся ответственность за освобождение памяти вызывающему. Не очень приятно по современным меркам, но работает.

0

Если вы решите не использовать стандартные методы управления памятью (т. Е. Std :: vector), тогда вам придется сделать выбор.

три основных варианта:

  1. Caller управляет памятью. Caller проходит в блоке памяти (и, вероятно, int, указывающем, насколько большой этот массив). Вы заполняете этот массив. Функция не требует выделения памяти.
  2. Callee управляет памятью. Функция выделяет достаточно большой блок, заполняет его, а затем возвращает указатель на него.
  3. Сотрудничество. Caller передает функцию обратного вызова, вызываемый использует эту функцию для выделения блока.

Вариант (2) осложняется тем, что кому-то нужно освободить память. Как часть API, вам нужно указать, будет ли функция каким-то образом очищать этот блок позже (и когда), или отвечает ли вызывающий.

Вариант (3), вероятно, излишний - вам нужно написать функцию только для вызова основной функции.

Вариант (1) является поэтому лучшим из лучших (если вы не можете использовать векторы). Это довольно стандартный шаблон - например, низкоуровневые API Windows используют этот шаблон.

В основном, управление памятью должно быть документировано как часть вашего API.

Смежные вопросы