简体   繁体   中英

How do you prevent leaks when raising an exception in init?

Here's the situation. Let's say I have a class called MYFoo. Here's it's initializer:

-init
{
  self = [super init];
  if (self)
  {
    // during initialization, something goes wrong and an exception is raised
    [NSException raise ...];
  }
  return self;
}

Now somewhere else I want to use a MYFoo object, so I use a common pattern:

MYFoo *foo = [[[MYFoo alloc] init] autorelease];

But what's going to happen is that, even if there's a try/catch around the 2nd part, a MYFoo object is going to be allocated, the exception will be thrown, the autorelease missed, and the uninitialized MYFoo object will leak.

What should happen here to prevent this leak?

The Apple Docs say the best practice is not to throw.

Handling Initialization Failure

In general, if there is a problem during an initialization method, you should call [self release] and return nil.

If you need to know what happened, you can init the object and have some kind of internal state that gets checked by the caller to ensure the object is usable.

ongle is 100% right. But if you do need to throw an exception and you do want to catch it somewhere (as opposed to just bailing out of the application), you can wrap your initialisation in @try { ... } @finally { ... }

-init
{
   self = [super init];
   if (self)
   {
       @try
       { 
           // during initialization, something goes wrong and an exception is raised
           @throw...
       }
       @finally
       {
           [self release]; 
       }
   }
   return self;
}

If you do the above, you should document that the init method can throw an exception because otherwise other users of your code will expect the default behaviour and possibly not write exception safe code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM