escher@Apple.COM (Michael Crawford) (07/11/90)
Can anyone suggest strategies for handling failed memory allocation in constructors? Constructors may not have return values, and aren't even void. I have seen some references to how there is not unified method, and one just needs to hack it. Example source code I have seen does not even address the issue, and just assumes the construction succeeds. The problem, as I see it, is that what one does upon memory failure depends greatly on the situation: do you crash and burn, wait, advise the user to close documents, or free a sentinel block (a large block allocated at the start of a program to provide a reserve) and retry the allocation? Here is a the problem: class foo { char *thePtr; public: CauseACrash(); foo(); ~foo(); } void theFun() { foo theFoo; // foo(), the constructor, gets called foo.CauseACrash(); // ~foo() gets called here, if we're still running! } foo::foo() { thePtr = NewPtr( 123456789 ); if ( thePtr == (char*)NULL ){ // Whadda I do? } } foo::CauseACrash() { int i; for ( i = 0; i < 123456789; i++ ){ *i = 'Q'; } } On a Mac, CauseACrash will scrawl all over the interrupt vector table; on Unix, it should core dump (if page 0 is mapped out, as good Unices do). Seems to me a member function ought to be able to assume that its instance is valid, and one should not have to validate every instance one creates; the fact that the object is dynamically allocated should be hidden to the user. This would mean that the failure should be handled within the constructor. I can conceive of some ways to do it, but I am a beginner here, and having enough trouble figuring out the language. Others must have invented this wheel before, care to roll one by me? I will summarize and post if you mail me suggestions, though this looks like a general enough problem to have an open discussion. Thank you very much, -- Michael D. Crawford Oddball Enterprises Consulting for Apple Computer Inc. 606 Modesto Avenue escher@apple.com Santa Cruz, CA 95060 Applelink: escher@apple.com@INTERNET# oddball!mike@ucscc.ucsc.edu The opinions expressed here are solely my own. alias make '/bin/make & rn'
fair@Apple.COM (Erik E. Fair) (07/11/90)
In the referenced article, escher@Apple.COM (Michael Crawford) writes:
on Unix, it should core dump (if page 0 is mapped out, as good Unices do).
Mike,
Deferencing address zero isn't a crime, unless it isn't in
your address space. There are lots of versions of UNIX where it is, and
that program won't crash and burn until you reach the bottom of your
allocated address space.
The reason that some UNIX systems don't map page zero, as you put it,
varies. Some do it because their hardware (or compiler) has things set
up so that a user program's address space doesn't begin in zero.
Some do it, because attempting to deference address zero is a very
common portability error (and more than occasionally, a logic error)
for the systems that don't have it mapped, particularly for those
programs which assume that location zero *contains* a zero of some
size. So some UNIX systems that might otherwise have address zero
mapped, don't do so, as an encouragement to write portable code.
So, dereferencing zero isn't a bad thing; it's just bad to assume that
you always can across all possible hardware architectures that your
program might be run on.
Erik E. Fair apple!fair fair@apple.com
imp@dancer.Solbourne.COM (Warner Losh) (07/12/90)
In article <42825@apple.Apple.COM> fair@Apple.COM (Erik E. Fair) writes: >So, dereferencing zero isn't a bad thing; it's just bad to assume that >you always can across all possible hardware architectures that your >program might be run on. Dereferencing "zero" is a bad thing. "0" is the Nil pointer in C and C++. It is defined to point to an address that doesn't exist (or is at least unique). So if you dereference it, you are asking for trouble. In most implementations of C and C++ a Nil pointer has all its bits turned off, but not all implementations do this. Regardless of the implementation, saying "p=0" will get you a Nil pointer. So if you then say *p, that is an error. However, according to the standard, compilers are free to not notify the user this error has occurred. -- Warner Losh imp@Solbourne.COM All the world is not a VAX. :-)
lsr@Apple.COM (Larry Rosenstein) (07/12/90)
In article <9075@goofy.Apple.COM> escher@Apple.COM (Michael Crawford) writes: > >Example source code I have seen does not even address the issue, and >just assumes the construction succeeds. > >The problem, as I see it, is that what one does upon memory failure >depends greatly on the situation: do you crash and burn, wait, advise >the user to close documents, or free a sentinel block (a large block The purpose of the constructor is to put the object in a known, consistent state. This doesn't necessarily mean it is in a valid or normal state. Probably the best approach is to have the contructor flag the invalid object, and have the other methods check the validity before proceeding. After the client creates the object, it can check to see if the creation succeeded. If it doesn't check, then error can be reported later, but at least everything is consistent, and the client can handle the error as it chooses. I don't think a constructor should try to decide what to do about the error (e.g., crash, advise the user, etc.); that's the function of higher levels of software. Freeing a sentinel block is a common approach on the Macintosh, but this is normally done at a lower level (within a Memory Manager GrowZoneProc). Another approach would be similar to what is done in Object Pascal. The constructor is set up to do initialization that can't fail, and there is a separate initialization step that the client has to explicitly call, which can return an error. (This makes things more complicated for the client, of course.) The issue isn't just that constructors don't return a value. One can always use setjmp/longjmp to break out of the constructor. The problem is recovering, which requires that destructors be invoked for automatic objects, for example. (The proposed C++ exception handling mechanism does this, for example.) >On a Mac, CauseACrash will scrawl all over the interrupt vector table; on True, but not very useful. -- Larry Rosenstein, Object Specialist Apple Computer, Inc. 20525 Mariani Ave, MS 46-B Cupertino, CA 95014 AppleLink:Rosenstein1 domain:lsr@Apple.COM UUCP:{sun,voder,nsc,decwrl}!apple!lsr
escher@Apple.COM (Michael Crawford) (07/13/90)
In article <1990Jul11.180345.21464@Solbourne.COM> imp@dancer.solbourne.com writes: >In article <42825@apple.Apple.COM> fair@Apple.COM (Erik E. Fair) writes: >>So, dereferencing zero isn't a bad thing; it's just bad to assume that >>you always can across all possible hardware architectures that your >>program might be run on. > >In most implementations of C and C++ a Nil pointer has all its bits >turned off, but not all implementations do this. Regardless of the >implementation, saying "p=0" will get you a Nil pointer. So if you >then say *p, that is an error. However, according to the standard, >compilers are free to not notify the user this error has occurred. According to me, no system that pretends to have protected memory has any excuse to not map out page 0. This, to me, is like buying a fancy car, and having them leave out the brakes. I understand it is perfectly legal to have it mapped in, as long as address 0 is either never used _or_ (void*)NULL does not have all 0 bits (this is not always the case in practice, as recently discussed in comp.unix.wizards), but I consider segmentation violations and core dumps to be extremely important debugging tools, and would not buy a protected-mode OS that did not do this. Of course the Macintosh doesn't, but it does not claim to have protected memory, and one is not paying for it. I program the mac because I find it aesthetically pleasing, but I also program on Unix (Sun particularly) because I find it easier to get things to work. -- Michael D. Crawford Oddball Enterprises Consulting for Apple Computer Inc. 606 Modesto Avenue escher@apple.com Santa Cruz, CA 95060 Applelink: escher@apple.com@INTERNET# oddball!mike@ucscc.ucsc.edu The opinions expressed here are solely my own. alias make '/bin/make & rn'