开发者

Returning a C-array and memory management

I am slightly bemused by the following property points of class MKMultiPoint in MapKit:

@property (nonatomic, readonly) MKMapPoint *points

It returns an array of struct. One can know the number of elements in the array with the pointCount property.

With my limited knowledge of C, I always thought C-arrays could only be "sort of returned" if passed by reference to a function because the caller is responsible for allocating the memory and then releasing it.

If I were to write a similar property, who woul开发者_运维知识库d allocate the memory for the array (presumably the callee) and more importantly who would free it (presumably the caller)? That sounds a bit risky to me. Besides, the documentation for the property above doesn't say anything about having to free memory.

What am I missing?


(The sample code is in C).

The good practice is to allocate and free a resource at the same level. There are two ways to define a function that returns an array of things:

// `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

The second way is to let the library function manage the memory:

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);


The receiver, in most cases, would handle allocating the memory. Who frees it depends on how you determine ownership. Is the memory allocated by the receiver no longer needed once it's returned? If so, you should probably note in your documentation that the caller needs to free the returned array. If the receiver can reuse the returned memory, leave deallocation to it.

If you wanted to leave it up to the callee to handle memory allocation, you probably wouldn't use a property and instead opt for a message and property like so:

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

where the sender should provide an existing buffer to store obj.mapPointCount number of MKMapPoints in. Then, you've placed the responsibility for allocation/deallocation on the caller.

If you don't want to go that route, and since the memory in question can't be retained/released/autoreleased by the receiver, I would leave it up to the caller to release it. If you want to make it somewhat clear that the memory is not to be freed, return it with the type const MKMapPoint * and note it in some form of documentation (which should hopefully make it clear that the memory is not owned by whoever accesses the data).

Alternatively, store it in an NSData or something and make it clear that once the next autorelease pool is drained, the pointer is invalid. However, that's a little less friendly, and possibly not safe with garbage collection. Probably wrong about that last bit, but I don't know enough to say, so I'll prefer caution for now.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜