Разве это плохо - возвращать указатель в виде кучи из функции? - PullRequest
1 голос
/ 22 июня 2011

До boost::shared_ptr считалось плохой практикой возвращать указатель, выделенный из кучи, из функции, так как вызывающий должен будет помнить free() этот объект?

Или это считалось"нормальный"?

Ответы [ 7 ]

11 голосов
/ 22 июня 2011

Я не считаю это плохой практикой, если ваш API также предоставляет эквивалентную функцию XXX_free (или XXX_close, XXX_clearup, или что-то еще), которую клиентский код может вызывать после завершения работы с указателем.

Таким образом, у вас есть согласованный, симметричный API, в том смысле, что ответственность за время жизни объекта кучи сохраняется в одном месте.

Этот подход также поддается болеекомплексное освобождение ресурсов.Например, если возвращаемый указатель относится к динамически распределяемой структуре, которая, в свою очередь, имеет члены, указывающие на динамически распределяемую память, вся процедура очистки может быть скрыта / удалена из клиентского кода.

2 голосов
/ 22 июня 2011

Вы пометили свой вопрос C. В C это очень часто встречается, например, fopen возвращает FILE *, который позже должен быть освобожден путем вызова fclose.

Если вы хотели пометить его C ++тогда все сложнее.Старые кодовые базы (середина 1990-х и ранее) часто передавали обнаженные указатели на объекты.Все коммерчески поддерживаемые библиотеки были основаны на этом шаблоне (OWL Borland, Microsoft MFC).

1 голос
/ 22 июня 2011

Вы найдете примеры обеих методологий: либо функция, выделяющая память и возвращающая указатель, либо функция, принимающая указатель на уже выделенное пространство.

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

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

Короткий ответ: решать вам. Действительно неправильный путь - выбрать что-то и быть непоследовательным или непонятным в интерфейсе.

1 голос
/ 22 июня 2011

Если вам нужно это сделать, то обычной практикой является предоставление собственной «свободной» функции, которая берет выделенный указатель и освобождает его. Это не позволяет пользователю использовать несовместимую бесплатную реализацию, которая может повредить память.

0 голосов
/ 28 июня 2011

На самом деле, лучшая идиома (используемая интерфейсами COM) состоит в том, чтобы потребовать создания указателя в вызывающей стороне до точки вызова функции и написать функцию, которая принимает двойной указатель.

Например :

    HRESULT CreateDevice(
      [in]           UINT Adapter,
      [in]           D3DDEVTYPE DeviceType,
      [in]           HWND hFocusWindow,
      [in]           DWORD BehaviorFlags,
      [in, out]      D3DPRESENT_PARAMETERS *pPresentationParameters,
      <b>[out, retval]  IDirect3DDevice9 **ppReturnedDeviceInterface</b>
    );

Таким образом, вызывающая сторона отвечает за создание указателя и вызов функции выделения, и поэтому с большей вероятностью не забудет вызвать функцию освобождения (что в случае с COM требует, чтобы вы вызывали метод ->Release() для объекта COM)

Но я думаю, что принятие функций создания / уничтожения в сочетании с передачей двойных указателей является лучшим способом напомнить получателю о выделенном объекте кучи для очистки после использования объекта.

Я согласен с Oli , что функции Create / Destroy гораздо более симметричны и существование функции Destroy должно превратить пользователя API в тот факт, что эти объекты, которые он получает от Функции создания не просто исчезают сами по себе, и их (Destroy fcns) нужно вызывать.

0 голосов
/ 22 июня 2011

Обычно вы бы возвращали указатель только из явной функции create_blah ()

Более распространенным является передача указателя (указателю), который, если он равен нулю, был выделен функцией.

0 голосов
/ 22 июня 2011

Это было и остается распространенным явлением, поскольку это практически единственный способ работать с библиотеками, созданными для разных сред выполнения в определенных операционных системах.Например, в Windows совместное использование нескольких библиотек времени выполнения VC ++ в одном исполняемом файле обычно будет работать правильно, только если библиотеки отвечают за все управление собственной памятью, включая как распределение объектов, так и удаление.shared_ptr и подобные инструменты на самом деле могут вызвать проблемы в этом случае.

При этом, как правило, имя функции и / или документация (если все сделано правильно) дают понять, что это происходит.Также было принято иметь соответствующую функцию DeleteXXX () для обработки бесплатного вызова.

...