About the fate of malloc()ed arrays of arrays
my first question on Stackoverflow.
Let me start with a bit of code. It's a bit repetitive so I'm going to cut out the parts I repeat for different arrays (feel free to ask for the o开发者_StackOverflowthers). However, please ignore the code in preference to answering the Qs at the bottom. Firstly: thank you to answerers in advance. Secondly: the freeing of data.
@implementation ES1Renderer
GLfloat **helixVertices;
GLushort **helixIndices;
GLubyte **helixColors;
- (void)freeEverything
{
if (helixVertices != NULL)
{
for (int i=0; i < alphasToFree / 30 + 1; i++)
free(helixVertices[i]);
free(helixVertices);
}
if (helixIndices != NULL)
{
for (int i=0; i < alphasToFree / 30 + 1; i++)
free(helixIndices[i]);
free(helixIndices);
}
if (helixColors != NULL)
{
for (int i=0; i < alphasToFree / 30 + 1; i++)
free(helixColors[i]);
free(helixColors);
}
}
(I will get to the calling of this in a moment). Now for where I malloc() the arrays.
- (void)askForVertexInformation
{
int nrows = self.helper.numberOfAtoms / 300;
int mrows = [self.helper.bonds count] / 300;
int alphaCarbonRows = [self.helper.alphaCarbons count] / 30;
helixVertices = malloc(alphaCarbonRows * sizeof(GLfloat *) + 1);
helixIndices = malloc(alphaCarbonRows * sizeof(GLfloat *) + 1);
helixColors = malloc(alphaCarbonRows * sizeof(GLfloat *) + 1);
for (int i=0; i < alphaCarbonRows + 1; i++)
{
helixVertices[i] = malloc(sizeof(helixVertices) * HELIX_VERTEX_COUNT * 3 * 33);
helixIndices[i] = malloc(sizeof(helixIndices) * HELIX_INDEX_COUNT * 2 * 3 * 33);
helixColors[i] = malloc(sizeof(helixColors) * HELIX_VERTEX_COUNT * 4 * 33);
}
[self.helper recolourVerticesInAtomRange:NSMakeRange(0, [self.helper.alphaCarbons count]) withColouringType:CMolColouringTypeCartoonBlue forMasterColorArray:helixColors forNumberOfVertices:HELIX_VERTEX_COUNT difference:30];
self.atomsToFree = self.helper.numberOfAtoms;
self.bondsToFree = [self.helper.bonds count];
self.alphasToFree = [self.helper.alphaCarbons count];
}
Finally, the bit which calls everything (this is a separate class.)
- (void)loadPDB:(NSString *)pdbToLoad
{
if (!self.loading)
{
[self performSelectorOnMainThread:@selector(stopAnimation) withObject:nil waitUntilDone:YES];
[self.renderer freeEverything];
[renderer release];
ES1Renderer *newRenderer = [[ES1Renderer alloc] init];
renderer = [newRenderer retain];
[self performSelectorOnMainThread:@selector(stopAnimation) withObject:nil waitUntilDone:YES]; // need to stop the new renderer animating too!
[self.renderer setDelegate:self];
[self.renderer setupCamera];
self.renderer.pdb = nil;
[renderer resizeFromLayer:(CAEAGLLayer*)self.layer];
[newRenderer release];
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(setup:) object:pdbToLoad];
[self.queue addOperation:invocationOperation];
[invocationOperation release];
}
}
- (void)setup:(NSString *)pdbToLoad
{
self.loading = YES;
[helper release];
[renderer.helper release];
PDBHelper *aHelper = [[PDBHelper alloc] initWithContentsOfFile:pdbToLoad];
helper = [aHelper retain];
renderer.helper = [aHelper retain];
[aHelper release];
if (!resized)
{
[self.helper resizeVertices:11];
resized = YES;
}
self.renderer.helper = self.helper;
[self.helper setUpAtoms];
[self.helper setUpBonds];
if (self.helper.numberOfAtoms > 0)
[self.renderer askForVertexInformation];
else
{
// LOG ME PLEASE.
}
[self performSelectorOnMainThread:@selector(removeProgressBar) withObject:nil waitUntilDone:YES];
[self performSelectorOnMainThread:@selector(startAnimation) withObject:nil waitUntilDone:YES];
self.renderer.pdb = pdbToLoad;
self.loading = NO;
}
What I'm doing here is loading a molecule from a PDB file into memory and displaying it on an OpenGL view window. The second time I load a molecule (which will run loadPDB:
above) I get the Giant Triangle Syndrome and Related Effects... I will see large triangles over my molecule.
However, I am releasing and reallocating my PDBHelper and ES1Renderer every time I load a new molecule. Hence I was wondering:
1. whether the helixVertices, helixIndices and helixColors which I have declared as class-wide variables are actually re-used in this instance. Do they point to the same objects?
2. Should I be setting all my variables to NULL after freeing? I plan to do this anyway, to pick up any bugs by getting a segfault, but haven't got round to incorporating it. 3. Am I even right to malloc() a class variable? Is there a better way of achieving this? I have no other known way of giving this information to the renderer otherwise.I can't answer your general questions. There's too much stuff in there. However, this caught my eye:
[helper release];
[renderer.helper release];
PDBHelper *aHelper = [[PDBHelper alloc] initWithContentsOfFile:pdbToLoad];
helper = [aHelper retain];
renderer.helper = [aHelper retain];
[aHelper release];
I think this stuff possibly leaks. It doesn't make sense anyway.
If renderer.helper is a retain or copy property, do not release it. It already has code that releases old values when it is assigned new values. Also do not retain objects you assign to it.
You have alloc'd aHelper, so there's no need to retain it again. The above code should be rewritten something like:
[helper release];
helper = [[PDBHelper alloc] initWithContentsOfFile:pdbToLoad];
renderer.helper = helper;
Also, I think your helix malloced arrays should probably be instance variables. As things stand, if you have more than one ES1Renderer, they are sharing those variables.
精彩评论