Memory leak if alloc succeeds but init fails?

  • Apple's Cocoa Memory Management Programming guide shows this pattern
    for init:

    - (id)init {
        if ((self = [super init])) {// superclass may return nil
            // your initialization code goes here
        }
        return self;
    }

    Newb question: In the case of
        id myObject = [[MyObject alloc]init];
    what happens to the allocated memory if the [super init] fails and
    how do I handle it since I dont have a self to release?

    Thx
    Russ
  • On 28/09/2007, at 3:10 PM, R.L. Grigg wrote:

    > Apple's Cocoa Memory Management Programming guide shows this
    > pattern for init:
    >
    > - (id)init {
    > if ((self = [super init])) {// superclass may return nil
    > // your initialization code goes here
    > }
    > return self;
    > }
    >
    > Newb question: In the case of
    > id myObject = [[MyObject alloc]init];
    > what happens to the allocated memory if the [super init] fails and
    > how do I handle it since I dont have a self to release?

    If [super init] fails it should have done [self release] before
    returning nil.

    - Chris
  • On Sep 27, 2007, at 10:12 PM, Chris Suter wrote:
    >
    > On 28/09/2007, at 3:10 PM, R.L. Grigg wrote:
    >
    >> Apple's Cocoa Memory Management Programming guide shows this
    >> pattern for init:
    >>
    >> - (id)init {
    >> if ((self = [super init])) {// superclass may return nil
    >> // your initialization code goes here
    >> }
    >> return self;
    >> }
    >>
    >> Newb question: In the case of
    >> id myObject = [[MyObject alloc]init];
    >> what happens to the allocated memory if the [super init] fails and
    >> how do I handle it since I dont have a self to release?
    >
    > If [super init] fails it should have done [self release] before
    > returning nil.

    Okay so somewhere along the chain up to NSObject, some class in the
    hierarchy is responsible for issuing [self release] within it's
    aborted init. But just theoretically if it does go all the way up to
    NSObject which fails its init, is it's alloced memory leaked? Not
    that it will ever happen...

    Russ
  • >> If [super init] fails it should have done [self release] before
    >> returning nil.
    >
    > Okay so somewhere along the chain up to NSObject, some class in the
    > hierarchy is responsible for issuing [self release] within it's
    > aborted init. But just theoretically if it does go all the way up
    > to NSObject which fails its init, is it's alloced memory leaked?
    > Not that it will ever happen...

    It will only leak if there is a bug. If you return nil from an init
    method you are responsible for releasing the object. If -[NSObject
    init] could fail, it would have to release the object.

    http://developer.apple.com/documentation/Cocoa/Reference/Foundation/
    Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/
    NSObject/init

    - Chris
  • Yes if you do not issue a release then the memory leaks.
    And yes if your [super init] call returns nil, then, whatever the
    calss is it's supposed to have cleaned up what it did.
    Depending on what does your dealloc method, it should check that what
    it frees has been alloced or initialized.

    Regards.

    On Sep 28, 2007, at 7:38 AM, R.L. Grigg wrote:

    > On Sep 27, 2007, at 10:12 PM, Chris Suter wrote:
    >>
    >> On 28/09/2007, at 3:10 PM, R.L. Grigg wrote:
    >>
    >>> Apple's Cocoa Memory Management Programming guide shows this
    >>> pattern for init:
    >>>
    >>> - (id)init {
    >>> if ((self = [super init])) {// superclass may return nil
    >>> // your initialization code goes here
    >>> }
    >>> return self;
    >>> }
    >>>
    >>> Newb question: In the case of
    >>> id myObject = [[MyObject alloc]init];
    >>> what happens to the allocated memory if the [super init] fails
    >>> and how do I handle it since I dont have a self to release?
    >>
    >> If [super init] fails it should have done [self release] before
    >> returning nil.
    >
    > Okay so somewhere along the chain up to NSObject, some class in the
    > hierarchy is responsible for issuing [self release] within it's
    > aborted init. But just theoretically if it does go all the way up
    > to NSObject which fails its init, is it's alloced memory leaked?
    > Not that it will ever happen...
    >
    > Russ
    >
  • > If [super init] fails it should have done [self release] before
    > returning nil.

    I have to say, I was surprised by this, but on thinking about it, of course
    it makes sense.

    However, then I read the online documentation to see if it was spelled out
    and found:

    http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes
    /

    NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/init

    which seems to contain two contradictory statements.

    "Subclass implementations of this method should initialize and return the
    new object. If it can't be initialized, they should release the object and
    return nil."

    ...snip...

    "Every class must guarantee that the init method either returns a fully
    functional instance of the class or raises an exception."

    It seems to me that these can't both be true.  You can't both 'return nil'
    and 'raise an exception'
  • On a syntactic point of view, 'nil' can be seen as a fully functional
    object, it can be distinguished from other instances easily.
    I suppose they meant that if the program wouldn't be able to tell a
    fully functional instance of a class from a non functional one, that is
    what the initialization returns cannot be interpreted as a failure or
    a success from its result, then the initialization methods
    must raise an exception to tell that something wrong happened.

    Still, this would be really weird to proceed this way in an init
    method. :-\

    On Sep 28, 2007, at 8:09 AM, Jeff Laing wrote:

    >> If [super init] fails it should have done [self release] before
    >> returning nil.
    >
    > I have to say, I was surprised by this, but on thinking about it,
    > of course
    > it makes sense.
    >
    > However, then I read the online documentation to see if it was
    > spelled out
    > and found:
    >
    > http://developer.apple.com/documentation/Cocoa/Reference/Foundation/
    > Classes/
    > NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/
    > NSObject/init
    >
    > which seems to contain two contradictory statements.
    >
    > "Subclass implementations of this method should initialize and
    > return the
    > new object. If it can't be initialized, they should release the
    > object and
    > return nil."
    >
    > ...snip...
    >
    > "Every class must guarantee that the init method either returns a
    > fully
    > functional instance of the class or raises an exception."
    >
    > It seems to me that these can't both be true.  You can't both
    > 'return nil'
    > and 'raise an exception'
    >
  • Hi Russ,
    You are not required to do anything. If superclass'
    initializer returns nil it means that there was an
    error and the instance has been already released.
    Similarly, if there is an error in your initializer,
    you are expected to release the object and return nil.

    Hope it helps,
    Gorazd

    ----------------------------------------

    Apple's Cocoa Memory Management Programming guide
    shows this pattern
    for init:

    - (id)init {
        if ((self = [super init])) {// superclass may
    return nil
            // your initialization code goes here
        }
        return self;
    }

    Newb question: In the case of
        id myObject = [[MyObject alloc]init];
    what happens to the allocated memory if the [super
    init] fails and
    how do I handle it since I dont have a self to
    release?

    Thx
    Russ

          Be smarter than spam. See how smart SpamGuard is at giving junk email the boot with the All-new Yahoo! Mail at http://mrd.mail.yahoo.com/try_beta?.intl=ca
  • El 28/9/2007, a las 8:29, Half Activist escribió:

    > On a syntactic point of view, 'nil' can be seen as a fully
    > functional object, it can be distinguished from other instances
    > easily.
    > I suppose they meant that if the program wouldn't be able to tell a
    > fully functional instance of a class from a non functional one,
    > that is
    > what the initialization returns cannot be interpreted as a failure
    > or a success from its result, then the initialization methods
    > must raise an exception to tell that something wrong happened.
    >
    > Still, this would be really weird to proceed this way in an init
    > method. :-\

    Exceptions should really only be used to signal programmer errors;
    that is failed assumptions (things you assume to be true).

    So I would say, return nil if the failure to initialize is caused by
    an external factor outside of your control, and raise an exception if
    your assumptions about what state should be true have not been met.

    As an obvious example, in the init method you *assume* that the
    programmer will pass the correct parameters according to the
    specifications that you make in the docs. This is an assumption, and
    an assumption is an expectation that you should test in order to
    catch programmer errors. You test this expectation and throw an
    exception if it is not met (ie. you use NSParameterAssert which
    throws an NSInternalInconsistencyException). But if there is
    something outside of your control (eg. you need to read a file but
    you find that you don't have access permission) you release yourself
    and return nil.

    Given that you raise exceptions only to indicate programmer errors,
    the little bit of leaked memory in the exception case is the last
    thing you need to worry about. You *could* release before throwing if
    you want, but why fix a leak in a code path that you expect to never
    take? Better to catch and fix programmer errors as soon as you find
    them.

    Not sure if I've described that very clearly, but hopefully you get
    the idea.

    Cheers,
    Wincent
  • > Exceptions should really only be used to signal programmer errors;
    > that is failed assumptions (things you assume to be true).
    >
    > So I would say, return nil if the failure to initialize is caused by
    > an external factor outside of your control, and raise an
    > exception if your assumptions about what state should be true have not
    been met.

    This is a subjective assessment, easily contradicted.  I think the failure
    of alloc to return me any memory would be 'an external factor outside of my
    control', but would not have expected it to happen.  Its definitely
    something that I cannot 'pre-check'.

    > throws an NSInternalInconsistencyException). But if there is
    > something outside of your control (eg. you need to read a file but
    > you find that you don't have access permission) you release yourself
    > and return nil.

    I can see where the same code path might fail for expected and unexpected
    reasons which you cannot discern from within the method.

    a) create a new object, initialising from a file that the user just selected
    b) create a new object, initialising from a file whose name I recorded
    earlier and stored in my 'uber-document'

    The object initialiser cannot know that in the first case, the file not
    existing would be evidence of a bug whereas in the second, its the result of
    the user having rearranged his file system.
  • El 1/10/2007, a las 1:36, Jeff Laing escribió:

    >> Exceptions should really only be used to signal programmer errors;
    >> that is failed assumptions (things you assume to be true).
    >>
    >> So I would say, return nil if the failure to initialize is caused by
    >> an external factor outside of your control, and raise an
    >> exception if your assumptions about what state should be true have
    >> not been met.
    >
    > This is a subjective assessment, easily contradicted.  I think the
    > failure
    > of alloc to return me any memory would be 'an external factor
    > outside of my
    > control', but would not have expected it to happen.  Its definitely
    > something that I cannot 'pre-check'.

    I totally agree with you. The success or otherwise of a memory
    allocation is something outside of your control, something whose
    success you should not "assume" and you should therefore check the
    result. I never said otherwise.

    Cheers,
    Wincent
  • Wincent Colaiuta (1/10/07, 15:23) said:

    >>> Exceptions should really only be used to signal programmer errors;
    >>> that is failed assumptions (things you assume to be true).
    >>>
    >>> So I would say, return nil if the failure to initialize is caused by
    >>> an external factor outside of your control, and raise an
    >>> exception if your assumptions about what state should be true have
    >>> not been met.
    >>
    >> This is a subjective assessment, easily contradicted.  I think the
    >> failure
    >> of alloc to return me any memory would be 'an external factor
    >> outside of my
    >> control', but would not have expected it to happen.  Its definitely
    >> something that I cannot 'pre-check'.
    >
    > I totally agree with you. The success or otherwise of a memory
    > allocation is something outside of your control, something whose
    > success you should not "assume" and you should therefore check the
    > result. I never said otherwise.

    The original comment (exceptions should only be used to signal
    programmer errors) is pretty questionable. Exceptions are designed to be
    used for any exceptional or unexpected behaviour, whether caused by a
    programmer error or by a system error.

    For example, C++ memory allocation automatically throws an exception if
    the memory could not be allocated. There is no result that you can check.

    Jeremy
  • On Oct 1, 2007, at 7:45 AM, Jeremy Hughes wrote:

    > For example, C++ memory allocation automatically throws an
    > exception if
    > the memory could not be allocated. There is no result that you can
    > check.

    ..unless you turn off exceptions or that feature. Then you check for
    NULL.

    -Shawn
  • El 1/10/2007, a las 16:45, Jeremy Hughes escribió:

    > The original comment (exceptions should only be used to signal
    > programmer errors) is pretty questionable. Exceptions are designed
    > to be
    > used for any exceptional or unexpected behaviour, whether caused by a
    > programmer error or by a system error.

    I guess my comments were made in the context of writing init methods,
    and the decision of how to indicate failure (by throwing or by
    returning nil). My general practice in that context is to return nil
    if something outside of my control went wrong (for example, super
    returned nil), throw an exception if there's a programmer error, and
    in most cases allow exceptions thrown by super or other classes that
    I interact with to fall through (this really falls under the
    "exceptional or unexpected behaviour" you talk about). But obviously
    this is just a general pattern and it can vary in specific cases; the
    most important thing is to uphold your end of your published API
    contract (as documented).

    > For example, C++ memory allocation automatically throws an
    > exception if
    > the memory could not be allocated. There is no result that you can
    > check.

    Obviously; you need to code to the API and the language you're
    working with. That means fulfilling required preconditions, passing
    the expected arguments, checking for documented return values, and
    being prepared to catch documented exceptions.

    Cheers,
    Wincent
previous month september 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Go to today