Declaration with three or more levels of pointer indirection
ID |
objectivec.maintainability.excessive_pointer_indirection |
Severity |
info |
Remediation Complexity |
hard |
Remediation Risk |
medium |
Remediation Effort |
medium |
Resource |
Complexity |
Language |
Objective-C |
Description
Reports a variable, parameter or out-parameter declared with three or more - float *grid, NSDictionary *tableOut. Two levels, the ordinary NSError * out-parameter shape, are not reported.
Rationale
Every extra * is another dereference the reader has to keep in their head and another pointer that can be null, uninitialised or already freed, and none of them is checked for you. The ownership question multiplies with the levels: who allocated the outer array of pointers, who frees the inner ones, and in what order, is not stated anywhere in the type. ARC is no help either, because it manages objects and not the arrays of pointers to them, so a three-level structure is hand-managed memory with the failure modes that implies.
The following code illustrates the pattern detected by this rule:
@implementation MatrixStore
- (void)buildGrid:(NSUInteger)rows columns:(NSUInteger)columns {
// FLAGGED: Declaration with three or more levels of pointer indirection
float ***grid = [self allocateGridWithRows:rows columns:columns];
// FLAGGED: Declaration with three or more levels of pointer indirection
char * * * names;
// FLAGGED: Declaration with three or more levels of pointer indirection
struct XYNode ****forest;
[self populate:grid names:names forest:forest];
}
@end
Remediation
Name the intermediate level with a typedef so each * has a meaning a reader can see, or replace the structure with an object: nested NSArray`s, an `NSMutableData holding a flat buffer with computed indices, or a small class that owns the storage and exposes accessors. A flat buffer plus row * width + column is usually both simpler and faster than an array of row pointers.