Lefora Free Forum
login join
Loading
862 views

string Release error in a loop

Page 1
1–7
regular - member
54 posts

I am working on a simple tab conversion for a ducimer. The loop below scans a "fret" number and converts it. The loop is only called for a fret that contains a special character, a tilde(~). An example fret is 2~1. This works but I am getting an error when I release theFret and specialFretChar, in the loop. I thought autorelease would work but I get a "double free" release error. The code works without the releases. After they are converted and appended to newTabLine they are not called directly again in my code. I hope this is enough code to understand what the problem is....if not I am more than willing to put more up.


            NSScanner *fretScanner = [NSScanner scannerWithString:thisFret];
            [fretScanner setCharactersToBeSkipped:nil];
               
            // a do while loop:
            while (![fretScanner isAtEnd])
            {
                NSString *theFret=[[NSString alloc] init];
                NSString *specialFretChar=[[NSString alloc] init];

                [fretScanner scanUpToString:@"~" intoString:&theFret];
                [fretScanner scanString:@"~" intoString:&specialFretChar]; //scan past this part
               
                [newTabLine appendString:[self convertFret:theFret]];
                [newTabLine appendString:specialFretChar];
               
                //[theFret release];
                //[specialFretChar release];
            }


Once again, thank you so very much,
Todd

?
288 posts

Todd

I'm rather surprised as this appears to violate my rule "please release me, if you m'alloced, and don't retain me any more".

You could move the alloc for theFret and specialFretChar outside the loop - and that would reduce the leak.  So have:

NSString* theFret = [NSString alloc] ;
NSString* specialFret = [NSString alloc];
while ( bla bla ) {
  theFret = [theFret init];
  specialFretChar = [specialFretChar init];
  bla bla
}

I'm also wondering if autoRelease would help.  For sure, we're both still a little puzzled by Obj/C Memory Management.

__________________
regular - member
54 posts

I tried autorelease and pretty much the same result. The reason I had alloc'd them inside the loop was to reinitialize it every time the loop runs and have a fresh clean var since it is an immutable string and I believe I had a problem similar before that using "NSString * xxx=yyy", xxx is always yyy and cannot be reset. I will try initing them outside of the loop and see what happens.

On a similar note possibly, when the scanner assigns its result to a var, it uses the ampersand and the var name. What does the "&" do? Could the scanner be releasing my vars and then I try and there is too much releasing going on?

The memory management is still perplexing me a bit and I am gradually learning to use it. I had read something somewhere that I think was declaring and releasing variables in a loop. The difference being their loop was of undetermined length and they were "being kind to memory" or something. Which makes sense.

Thank you for the reply Robin,

Todd

?
288 posts

This is very interesting.  I'll have a closer look after work this evening.  When we've solved this, we'll be in a better place.

The & passes the address.  So, you shouldn't alloc/init theFret, or specialFretChar, because scanUpToString's going to do it for you.

Here's my version of your code (which I'm playing with from a command-line program.

#import <Foundation/Foundation.h>



NSString* convertFret(NSString* f) { return f ; }


int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


NSMutableString* newTabLine = [[NSMutableString alloc]init];

NSString* thisFret = @"...~xxx~bbb~";

    

NSScanner *fretScanner = [NSScanner scannerWithString:thisFret];

[fretScanner setCharactersToBeSkipped:nil];


int count = 0 ;


// a do while loop:

while (![fretScanner isAtEnd])

{

NSString *theFret; //=[[NSString alloc] init];

NSString *specialFretChar; // =[[NSString alloc] init];


[fretScanner scanUpToString:@"~" intoString:&theFret];

[fretScanner scanString:@"~" intoString:&specialFretChar]; //scan past this part


[newTabLine appendString:convertFret(theFret)]; // [self convertFret:theFret]];

[newTabLine appendString:specialFretChar];


//[theFret release];

//[specialFretChar release];

NSLog(@"count = %d",count++) ;

}




    NSLog(@"Hello, World! newTabLine = %@",newTabLine);

[newTabLine release];


    [pool drain];

    return 0;

}

__________________
?
288 posts

Hi Todd

I've done a little messing with this.  I've added defines for POOL and OURNEWTAB - and I've added some comments.  I think he behaves in a sane way when POOL is set.  He's insane when POOL is not set.  So there's something mysterious about an init/alloc/constructor of the nature:

NSSomething = [NSSomething somethingThisAndThat] ; // leaks if there's no pool

However when the pool's in place, the cocoa country'n'western blues seems to work "Please release if you m'alloced, and don't retain me any more".  One day, I'll wake up and say "of course, I understand how the pool works" - in the meanwhile, our code's gonna leak a bit! (or even a lot).

For sure, it's clear when you pass a pointer to a pointer, you never release.  You only release if you alloc or retain.  Another example of this pointer to a pointer thing is our old adversary 

- (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError

You call him as:
NSError* error =nil;
[ document readFromURL ...... error:&error] ;

In other words, we're saying we don't have an error (error=nil), however if readFromURL decides to panic, he'll tell us by 'filling in' error.  How does the error object get released?  I don't know, I think that must be something to do with the pool.

One day, we'll get our head round this confusing arrangement.  You never know, maybe somebody from Apple will come to the forum and explain this to us.


#import <Foundation/Foundation.h>

NSString* convertFret(NSString* f) { return f ; }

#define POOL 1
#define OURNEWTAB 1

int main (int argc, const char * argv[])
{
#if POOL
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
#endif
NSMutableString* newTabLine = 

#if OURNEWTAB
[[NSMutableString alloc]init];
#else
[NSMutableString string];
#endif

NSString* thisFret = @"...~xxx~bbb~";
    
NSScanner* fretScanner = [NSScanner scannerWithString:thisFret];
[fretScanner setCharactersToBeSkipped:nil];

int count = 0 ;

// a do while loop:
while (![fretScanner isAtEnd])
{
NSString* theFret; //=[[NSString alloc] init];   // DON'T ALLOC fretScanner will do it
NSString* specialFretChar; // =[[NSString alloc] init]; // ditto

[fretScanner scanUpToString:@"~" intoString:&theFret];
[fretScanner scanString:@"~" intoString:&specialFretChar]; //scan past this part

[newTabLine appendString:convertFret(theFret)]; // [self convertFret:theFret]];
[newTabLine appendString:specialFretChar];

//[theFret release];  // DON'T RELEASE, we didn't ALLOC
//[specialFretChar release]; // ditto
NSLog(@"count = %d",count++) ;
}

    NSLog(@"Hello, World! newTabLine = %@",newTabLine);

#if OURNEWTAB
[newTabLine release]; // let him go, he's ours
#endif

#if POOL
[pool drain];
#endif

    return 0;
}

__________________
regular - member
54 posts

Robin,
            After I posted my first post here, I had noticed I didn't need to alloc  thefret and specialFret and just declared them, and left it at that.

So what you have discovered is that the & in the scanner is alloc'ing and initing, but not releasing and that is the reason for the pool, correct? So in a nutshell if you use the scanner and & sign you need to set up a pool?

I am at a point now where I understand alot of cocoa and NEED to go back and read the chapters and articles on memory management again. I am absolutely positive my code leaks like a sieve, but it works and that is encouraging.

So on a similar note, anytime you use a line of code like:

NSString *someVar;

Does an NSAutoreleasePool need to be set up?




Also for anyone who may be interested, I had a small revelation about allocing vars. Until now I have been trying not to alloc vars, thus avoiding having to release them. But I had some code where I needed to to repeatedly append something to a nsmutablestring within a loop, but if the nsmutablestring is not alloc'd and inited the append failed. initing and allocing fixed this, even if the string was empty when trying to append something to it.

Todd

?
288 posts

Hi Todd

Together we're getting there.  After I wrote on Wednesday evening, I had a little read at "the book" (Aaron's book of course [3rd Edition]) and his explanation of autorelease (page 73 or so)  I was still confused.  Well, it was late and I'd worked for 12+ hours!

On Thursday morning: Blinding Flash !!! on the way to Adobe (where I'm a contractor).  Autorelease pool says "don't release until the pool is drained".  That's how [NSSomething somethingXxxxx] works and doesn't leak.  It returns [xxx autorelease]; It returns a pointer that's valid until the next drain!  

Now, the event manager puts a pool in place before every event call (and drains it afterwards).  That's why it works.  And that's why my main() needs a pool.  Eureka!

To answer (part of) your question, does an NSAutoreleasePool need to be set up?  Answer: Yes and it's normally setup in a gui/event-loop context.  In main(), the programmer has to take care of it.
NSAnything [NSAnything anythingXxxxx] ; // you gotta have a pool.

There's two sides to memory leaks:

1) The good side
- they don't cause crashes!

2) The bad side
- they eat the computer!
- development compile/run/debug/terminate cycles don't reveal leaks!

We're almost there. I'm also going to re-read Apple's Memory Management Documentation.  Apple's documentation is excellant and like all reference documentation, the reader has to understand the system to understand what's being said.

So sure, I encourage you to revisit your code and I'll review my tutorials for leaks. There must be better leak detection tools - maybe shark.
Another month, Todd and we'll wonder why we were every confused by this!
To be continued .......... 

__________________
Page 1
1–7

Locked Topic


You must be a member to post in this forum

Join Now!