Возврат C-массива и управление памятью - PullRequest
3 голосов
/ 22 марта 2011

Меня слегка смущает следующее свойство points класса MKMultiPoint в MapKit:

@property (nonatomic, readonly) MKMapPoint *points

Возвращает массив struct.Можно узнать количество элементов в массиве с помощью свойства pointCount.

С моим ограниченным знанием C я всегда думал, что C-массивы могут быть «как бы возвращены», только если они переданы по ссылке нафункция, потому что вызывающая сторона отвечает за выделение памяти, а затем освобождает ее.

Если бы я написал подобное свойство, кто бы выделил память для массива (предположительно вызываемого) и, что более важно, кто его освободит(предположительно звонящий)?Это звучит немного рискованно для меня.Кроме того, в документации по указанному выше свойству ничего не говорится о необходимости освобождения памяти.

Что мне не хватает?

Ответы [ 2 ]

3 голосов
/ 22 марта 2011

(пример кода в C).

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

// `points` are allocated and freed by the caller.
void MakePoints (MKMapPoint *points, size_t number_of_points);

// usage:
size_t count = 10;
MKMapPoint *points = malloc (sizeof (MKMapPoint) * 10);
MakePoints (points, count);

// Use points

free (points);

// or simply
MKMapPoint points[10];
MakePoints (points, 10);

// Use points

Второй способ - позволить библиотечной функции управлять памятью:

MKMapPoint *MakePoints (size_t number_of_points);
void FreePoints (MKMapPoint *points);

// Usage:
MKMapPoint *points = MakePoints (10);

// Use points

// The library need not necessarily call free() on points,
// it might reuse it in further calls to MakePoints().
FreePoints (points);
0 голосов
/ 22 марта 2011

Приемник в большинстве случаев будет обрабатывать выделение памяти. Кто освобождает, зависит от того, как вы определяете право собственности. Память, выделенная получателю, больше не нужна после его возвращения? Если это так, вы, вероятно, должны отметить в своей документации, что вызывающая сторона должна освободить возвращенный массив. Если получатель может повторно использовать возвращенную память, оставьте для нее освобождение.

Если вы хотите передать вызываемому объекту распоряжение о распределении памяти, вы, вероятно, не будете использовать свойство и вместо этого выберете сообщение и свойство, например:

- (NSUInteger) mapPointCount;
- (void) getMapPoints:(MKMapPoint *)pointsOut;

, где отправитель должен предоставить существующий буфер для хранения obj.mapPointCount количества MKMapPoints. Затем вы возлагаете ответственность за распределение / освобождение на вызывающего.

Если вы не хотите идти по этому пути, и, поскольку рассматриваемая память не может быть сохранена / освобождена / автоматически освобождена получателем, я оставляю ее вызывающей стороне, чтобы освободить ее. Если вы хотите прояснить, что память не подлежит освобождению, верните ее с типами const MKMapPoint * и , отметьте это в какой-то форме документации (которая, как мы надеемся, должна дать понять, что память не принадлежит тем, кто получает доступ к данным).

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

...