Prev: ideas for data binding?
Next: Low memory conditions (was: Re: CoW and reference counting in the STL)
From: Goran on 29 Apr 2010 22:32 On Apr 30, 1:04 pm, Scott Meyers <NeverR...(a)aristeia.com> wrote: > I've asked a lot of questions about C++0x recently, so let me emphasize that I'm asking about current C++ (C++03) here. > > Consider: > > Widget *pwa = new Widget[100]; > ... > delete [] pwa; > > Suppose that the destructor for pwa[50] throws. What happens next? 15.1 > tells me that "control is transferred to the nearest handler with a > matching type," but 5.3.5/6 tells me that in a delete expression for an > array, "the elements will be destroyed in order of decreasing address (that > is, in reverse order of the completion of their constructor." So are > destructors invoked for array elements 0-49? > > My sense is that when pwa[50]'s destructor throws, the delete expression is > essentially abandoned (much as a looping expression would be abandoned if > an exception occurred during iteration), elements 0-49 of the array are not > destroyed, and the memory occupied by the array is not reclaimed by > operator delete (because that would have been performed by the > now-abandoned part of the delete expression), but I'd like to have more to > go on than how I sense things. So is the behavior of the above spelled out > by the standard? "Doctor, it hurts when I poke myself in the eye!" much? I don't know if it's spelled out in the standard, but I would be HUGELY surprised if any compiler's generated code would continue to call dtors etc after an exception was thrown. That would essentially mean that operator delete[] is (warning: compiled with head-compiler and tried with head-debugger): template<typename TYPE> void OperatorArrayDelete(TYPE* pBegin) { TYPE* pEnd = pBegin+ElementCount(pBegin); while (pEnd!= pBegin) try { (*--pEnd)->~Type(); } catch(...) {} // Well, that catch(...) {} smells to high heaven! SomehowFreeHeap(pBegin); } 15.1.must take precedence over 5.3.5/6. It must!!! Aaaaaarghhhhh! :-) Goran. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Nick Hounsome on 30 Apr 2010 02:17 On 30 Apr, 12:04, Scott Meyers <NeverR...(a)aristeia.com> wrote: > I've asked a lot of questions about C++0x recently, so let me emphasize that I'm asking about current C++ (C++03) here. > > Consider: > > Widget *pwa = new Widget[100]; > ... > delete [] pwa; > > Suppose that the destructor for pwa[50] throws. What happens next? 15.1 > tells me that "control is transferred to the nearest handler with a > matching type," but 5.3.5/6 tells me that in a delete expression for an > array, "the elements will be destroyed in order of decreasing address (that > is, in reverse order of the completion of their constructor." So are > destructors invoked for array elements 0-49? > > My sense is that when pwa[50]'s destructor throws, the delete expression is > essentially abandoned (much as a looping expression would be abandoned if > an exception occurred during iteration), elements 0-49 of the array are not > destroyed, and the memory occupied by the array is not reclaimed by > operator delete (because that would have been performed by the > now-abandoned part of the delete expression), but I'd like to have more to > go on than how I sense things. So is the behavior of the above spelled out > by the standard? > > Secondarily, is the behavior specified by C++0x any different? > > Thanks, > > Scott I don't remember what it says in the standard but I did once read a good description of why an implementation can never "do the the right thing" in general which boils down to the question "What would you do if 2 (or more) of the dtors threw? (elements 3 and 6 say)" There is no way an implementation could throw/handle exceptions for both so an implementation would either have to silently catch and ignore all but the first (or last) exception or stop prematurely as you suggest and the latter is clearly the least evil. In view of the impossibility of getting anything right in the presence of throwing dtors (It is well known that you can't gaurantee the post conditions of many STL methods and hence the std provides specific restrictive wording) It seems to me that the std ought to ban exceptions from dtors everywhere explicitly - or at least call std::unexpected/std::terminate but as far as I can see in N3000 it's the same old stuff (including the bit about destruction in reverse order) A quick google shows that according to http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#219 it's still an open issue for C++0x which confuses me because I thought that it was supoosed to be all done and dusted apart from dotting i's and crossing t's. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: cpp4ever on 30 Apr 2010 02:19 On 04/30/2010 02:32 PM, Goran wrote: > On Apr 30, 1:04 pm, Scott Meyers <NeverR...(a)aristeia.com> wrote: >> I've asked a lot of questions about C++0x recently, so let me emphasize that I'm asking about current C++ (C++03) here. >> >> Consider: >> >> Widget *pwa = new Widget[100]; >> ... >> delete [] pwa; >> >> Suppose that the destructor for pwa[50] throws. What happens next? 15.1 >> tells me that "control is transferred to the nearest handler with a >> matching type," but 5.3.5/6 tells me that in a delete expression for an >> array, "the elements will be destroyed in order of decreasing address (that >> is, in reverse order of the completion of their constructor." So are >> destructors invoked for array elements 0-49? >> >> My sense is that when pwa[50]'s destructor throws, the delete expression is >> essentially abandoned (much as a looping expression would be abandoned if >> an exception occurred during iteration), elements 0-49 of the array are not >> destroyed, and the memory occupied by the array is not reclaimed by >> operator delete (because that would have been performed by the >> now-abandoned part of the delete expression), but I'd like to have more to >> go on than how I sense things. So is the behavior of the above spelled out >> by the standard? > > "Doctor, it hurts when I poke myself in the eye!" much? > > I don't know if it's spelled out in the standard, but I would be > HUGELY surprised if any compiler's generated code would continue to > call dtors etc after an exception was thrown. That would essentially > mean that operator delete[] is (warning: compiled with head-compiler > and tried with head-debugger): > > template<typename TYPE> > void OperatorArrayDelete(TYPE* pBegin) > { > TYPE* pEnd = pBegin+ElementCount(pBegin); > while (pEnd!= pBegin) > try { (*--pEnd)->~Type(); } catch(...) {} > // Well, that catch(...) {} smells to high heaven! > SomehowFreeHeap(pBegin); > } > > 15.1.must take precedence over 5.3.5/6. It must!!! Aaaaaarghhhhh! :-) > > Goran. > > Goran has a damn fine point, depends where the exception is caught, and what it then does. IMHO if you get an unexpected exception in a destructor then something is potentially broken, and badly! Personally I often spend more time on constructors and destructors than most other member functions to avoid exceptions there. Getting it right is easier than debugging, especially in those situations. Regards JB -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Goran on 1 May 2010 05:26 On Apr 30, 7:19 pm, cpp4ever <n2xssvv.g02gfr12...(a)ntlworld.com> wrote: > On 04/30/2010 02:32 PM, Goran wrote: > >> On Apr 30, 1:04 pm, Scott Meyers <NeverR...(a)aristeia.com> wrote: >>> I've asked a lot of questions about C++0x recently, so let me emphasize that I'm asking about current C++ (C++03) here. > >>> Consider: > >>> Widget *pwa = new Widget[100]; >>> ... >>> delete [] pwa; > >>> Suppose that the destructor for pwa[50] throws. What happens next? 15.1 >>> tells me that "control is transferred to the nearest handler with a >>> matching type," but 5.3.5/6 tells me that in a delete expression for an >>> array, "the elements will be destroyed in order of decreasing address (that >>> is, in reverse order of the completion of their constructor." So are >>> destructors invoked for array elements 0-49? > >>> My sense is that when pwa[50]'s destructor throws, the delete expression is >>> essentially abandoned (much as a looping expression would be abandoned if >>> an exception occurred during iteration), elements 0-49 of the array are not >>> destroyed, and the memory occupied by the array is not reclaimed by >>> operator delete (because that would have been performed by the >>> now-abandoned part of the delete expression), but I'd like to have more to >>> go on than how I sense things. So is the behavior of the above spelled out >>> by the standard? > >> "Doctor, it hurts when I poke myself in the eye!" much? > >> I don't know if it's spelled out in the standard, but I would be >> HUGELY surprised if any compiler's generated code would continue to >> call dtors etc after an exception was thrown. That would essentially >> mean that operator delete[] is (warning: compiled with head-compiler >> and tried with head-debugger): > >> template<typename TYPE> >> void OperatorArrayDelete(TYPE* pBegin) >> { >> TYPE* pEnd = pBegin+ElementCount(pBegin); >> while (pEnd!= pBegin) >> try { (*--pEnd)->~Type(); } catch(...) {} >> // Well, that catch(...) {} smells to high heaven! >> SomehowFreeHeap(pBegin); >> } > >> 15.1.must take precedence over 5.3.5/6. It must!!! Aaaaaarghhhhh! :-) > >> Goran. > > Goran has a damn fine point, depends where the exception is caught, and > what it then does. IMHO if you get an unexpected exception in a > destructor then something is potentially broken, and badly! Personally I > often spend more time on constructors and destructors than most other > member functions to avoid exceptions there. Getting it right is easier > than debugging, especially in those situations. OK, but there's nothing wrong in throwing from a constructor. In fact, that's by far the best method of signaling construction errors. If you are trying to avoid an exception from a constructor, you are most likely using two-phase initialization almost all the time. And if you do that, you are raising the danger of having objects that you can't use (because e.g. a File object is useless if not "Open"; do you pre- pend every read with "isOpen", or do you just cross fingers that you did open it?). Goran. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Goran on 1 May 2010 21:49 On Apr 30, 7:28 pm, Scott Meyers <NeverR...(a)aristeia.com> wrote: >> I don't know if it's spelled out in the standard, but I would be >> HUGELY surprised if any compiler's generated code would continue to >> call dtors etc after an exception was thrown. > > Somehow I think that "the language's behavior should not cause huge > surprises" is not among its most influential design criteria. > Heck, entire books have been written about the kinds of things people need > to watch out for :-) True, that. After years of C++-ing, I seldom wonder why language I does what it does. But I indeed see a lot of people being amazed about X or Y. I don't know if that's saying something good or bad about me. Goran. P.S. We need this Daniel guy now, he's the resident expert in closing the discussion by quoting the standard around here. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
|
Next
|
Last
Pages: 1 2 3 Prev: ideas for data binding? Next: Low memory conditions (was: Re: CoW and reference counting in the STL) |