Google Gruppi non supporta più i nuovi post o le nuove iscrizioni Usenet. I contenuti storici continuano a essere visibili.

Exceptions from Constructors for classes with vector members

3 visualizzazioni
Passa al primo messaggio da leggere

John Pagakis

da leggere,
12 gen 1999, 03:00:0012/01/99
a
// I have run into a problem with a class I've built. This example strips
away all but the
// problem.
//
// classWithVector has one private data member - a vector of strings. The
constructor simply
// throws a string exception. Apparantly before my exception is thrown, an
Access Violation
// is thrown, which is what is caught by the elipsis catch block. Remove
the elipsis block
// and you get the Access Violation error in all its red x glory.
//
// Obviously, the stack unwinding is causing the vector< string > member
great discomfort.
// My question is, is this correct behavior, or is this breakage in the
compiler (I'm using
// VC++ 5.0 with Service Pack 3)?
//
// I'd be very interested in seeing if this code breaks in UNIX. If it
does, that would
// indicate that this is expected behavior, and I am missing some basic
understanding. Why
// would throwing an exception out of a constructor for a class with a
vector< string > member
// cause an access violation?

// John Pagakis - pag...@swlink.net

//------ testMain.cpp ------------ //
#pragma warning(disable: 4786)
#include <string>
#include <vector>
#include <iostream>
#include <stdlib.h>
#include "classWithVector.h"


int main()
{

try
{
classWithVector cwv;
}

catch ( string s )
{
cout << s << endl;
}

catch ( ... )
{
cout << "See what I mean?" << endl;
}

return ( 0 );

}


//---- classWithVector.h -----//
#include <vector>
#include <string>

using namespace std;

class classWithVector
{
private:
vector< string > m_strVect;

public:
classWithVector() { throw "Ka Boom!!"; }
~classWithVector() {};
};


John Pagakis

da leggere,
12 gen 1999, 03:00:0012/01/99
a
Sorry, I put my original question in comments in the code, it looked fine
when I sent it, but it posted horribly!!

I have run into a problem with a class I've built. This example strips

away all but the problem.

classWithVector has one private data member - a vector of strings. The

constructor simply throws a string exception. Apparantly before my
exception is thrown, an Access Violation is thrown, which is what is
caught by the elipsis catch block. Remove the elipsis block and you get


the Access Violation error in all its red x glory.

Obviously, the stack unwinding is causing the vector< string > member great
discomfort. My question is, is this correct behavior, or is this breakage
in the compiler (I'm using VC++ 5.0 with Service Pack 3)?

I'd be very interested in seeing if this code breaks in UNIX. If it does,

that would indicate that this is expected behavior, and I am missing some
basic understanding. Why would throwing an exception out of a constructor
for a class with a vector< string > member cause an access violation?

Jamie Hamilton

da leggere,
12 gen 1999, 03:00:0012/01/99
a
You are throwing a character array and trying to
catch a string.

>
> catch ( string s )
> {
> cout << s << endl;
> }

> public:
> classWithVector() { throw "Ka Boom!!"; }
>

Doug Harrison

da leggere,
12 gen 1999, 03:00:0012/01/99
a
John Pagakis wrote:

>// I have run into a problem with a class I've built. This example strips
>away all but the
>// problem.
>//
>// classWithVector has one private data member - a vector of strings. The
>constructor simply
>// throws a string exception. Apparantly before my exception is thrown, an
>Access Violation
>// is thrown, which is what is caught by the elipsis catch block. Remove
>the elipsis block
>// and you get the Access Violation error in all its red x glory.
>
>// Obviously, the stack unwinding is causing the vector< string > member
>great discomfort.
>// My question is, is this correct behavior, or is this breakage in the
>compiler (I'm using
>// VC++ 5.0 with Service Pack 3)?

Your code is fine, but what were your compiler options? That's apparently a
VC5 bug that was fixed in VC6. Under VC6, SP1, I get an "abnormal program
termination" error message when I remove the catch(...) clause, compile with
"cl -GX a.cpp", and run the program. This error message is due to the
uncaught exception and is expected. However, you touched on another problem.

There is a long-standing problem with VC's catch(...) implementation. It has
always caught untranslated Win32 structured exceptions (SEs), such as access
violations, zero-divides, etc., whose type isn't even expressible in C++.
Starting with VC5, using the default -GX option implied a new option, -EHs,
which is supposed to defeat this, because it is intended to support only
synchronous exceptions, i.e. true C++ exceptions. When -EHs is in effect in
optimized builds, VC will elide the try/catch machinery from a function, if
it can determine the tried code cannot throw a C++ exception. VC6 improved
on VC5 in performing this optimization on a wider basis. However, when the
optimization cannot be performed, which is probably most of the time,
catch(...) still catches untranslated SEs.

>// I'd be very interested in seeing if this code breaks in UNIX. If it
>does, that would
>// indicate that this is expected behavior, and I am missing some basic
>understanding.

The intent of the C++ catch(...) was always to catch only C++ exceptions,
not OS-specific, asynchronous things like Win32 SEs and Unix signals.

>Why
>// would throwing an exception out of a constructor for a class with a
>vector< string > member


>// cause an access violation?

It shouldn't. That's a bug, and catch(...) catching the access violation is
also a bug, IMO.

>// John Pagakis - pag...@swlink.net


>
>//------ testMain.cpp ------------ //
>#pragma warning(disable: 4786)
>#include <string>
>#include <vector>
>#include <iostream>
>#include <stdlib.h>
>#include "classWithVector.h"
>
>
>int main()
>{
>
> try
> {
> classWithVector cwv;
> }
>

> catch ( string s )

This is better written as:

catch (string& s)

Catching by reference may avoid copying the thrown string into s. Also, the
above won't catch the string literal you throw in your ctor. You need a
catch(char*) clause, because only limited conversions are performed in this
context. The C++ Standard lists them in 15.3/3. Roughly speaking, it's
limited to identity, derived to accessible base, and standard pointer and
qualification conversions. Construction of a std::string from a char*
doesn't fall into any of these categories.

> {
> cout << s << endl;
> }
>
> catch ( ... )
> {
> cout << "See what I mean?" << endl;
> }
>
> return ( 0 );
>
>}
>
>
>//---- classWithVector.h -----//
>#include <vector>
>#include <string>
>
>using namespace std;
>
>class classWithVector
>{
> private:
> vector< string > m_strVect;
>

> public:
> classWithVector() { throw "Ka Boom!!"; }
>

> ~classWithVector() {};
>};
>
>

P.S. When posting code, please watch your line length, because your
newsreader wrapped all your comments, making it difficult to read, and
impossible to compile without deleting them.

--
Doug Harrison
dHar...@worldnet.att.net


pS

da leggere,
12 gen 1999, 03:00:0012/01/99
a
Hi John,

So having fun with STL nowadays I c.

Jamie Hamilton is right on this topic.
> classWithVector() { throw "Ka Boom!!"; }

change it to
> classWithVector() { throw string ("Ka Boom!!"); }
shouldn't bomb.

Throwing an exception in the constructor is perfectly acceptable and it
shouldn't cause problem.

Phil.

PS: my email isn't working right these days. I am reconfiguring the server.

Jamie Hamilton wrote in message <77flke$896$1...@news1.Radix.Net>...


>You are throwing a character array and trying to
>catch a string.
>
>>

>> catch ( string s )

>> {
>> cout << s << endl;

Spam Hater

da leggere,
13 gen 1999, 03:00:0013/01/99
a

I always that that it was convenient that catch(...) was able to catch
win32 SEs and so forth. This way I had complete confidence that
catch(...) would truly catch anything. It would be nice if C++ had
some sort of official way to map SEGV (and others) to C++ exceptions.

You can set up a handler (via SetUnhandledExceptionFilter) where you
can throw an appropriate C++ exception for each win32 exception. You
have to take into account folks that might have called signal().

Spam Hater


On Tue, 12 Jan 1999 06:47:43 -0800, dHar...@worldnet.att.net (Doug
Harrison) wrote:
.
.


.
>There is a long-standing problem with VC's catch(...) implementation. It has
>always caught untranslated Win32 structured exceptions (SEs), such as access
>violations, zero-divides, etc., whose type isn't even expressible in C++.
>Starting with VC5, using the default -GX option implied a new option, -EHs,
>which is supposed to defeat this, because it is intended to support only
>synchronous exceptions, i.e. true C++ exceptions. When -EHs is in effect in
>optimized builds, VC will elide the try/catch machinery from a function, if
>it can determine the tried code cannot throw a C++ exception. VC6 improved
>on VC5 in performing this optimization on a wider basis. However, when the
>optimization cannot be performed, which is probably most of the time,
>catch(...) still catches untranslated SEs.

.
.

John Pagakis

da leggere,
13 gen 1999, 03:00:0013/01/99
a
Phil Sine I presume!!

Get your email working already!!

Check out my response to Jamie - The actual code I'm having trouble with is
attached there. My example was written at 1AM and does not illustrate the
problem <sigh>. The attached code *IS* the problem <evenBiggerSigh>!!

Hope you had a great holiday - looks like we picked a good time to leave
Chicago <g>!!

Talk to you soon old friend ....

JP

Doug Harrison

da leggere,
14 gen 1999, 03:00:0014/01/99
a
Spam Hater wrote:

>I always that that it was convenient that catch(...) was able to catch
>win32 SEs and so forth. This way I had complete confidence that
>catch(...) would truly catch anything.

The problem is that C++ exceptions and SEs represent very different things,
and it's hard to use either correctly when you mix the two in catch(...).

For example, suppose you have an outer __try/__except block whose purpose is
to trap access violations, commit virtual memory, and resume the failed
instruction. An inner catch(...) that doesn't rethrow will defeat this
completely, while one that does rethrow may have executed code that was
intended to deal with an error in the C++ program, which is what C++
exceptions are all about. See the CPropertySheet::DoModal documentation for
a description of a similar problem.

Now, suppose you had the following sequence:

// Begin C++ exception-free code.
... // Causes an access violation due to a bug.
// End C++ exception-free code.

The inner part updates a critical data structure, and the programmer assumes
it runs to completion. But if there is some outer catch(...) clause, it will
catch the SE, and the program will likely continue to run, having corrupted
its state, and all bets are off. The bug will probably manifest itself in
strange ways, in far removed code, and instead of going directly to the
cause of the bug via the OS-provided Application Error dialog box, you'll
have a difficult bug hunt on your hands, if you even notice the bug.

One thing that absolutely needs to use catch(...) is an application
framework, such as MFC. But MFC currently can't use catch(...) without
subjecting its users to the problems described above and others. The result
is that an uncaught C++ exception terminates an MFC program, which is kind
of serious, given that VC's C++ Standard Library and compiler COM support
both raise non-MFC exceptions. These libraries are useful in MFC programs,
and the only way to account for this shortcoming is to guard every function
that can exit via a non-MFC exception with something like the following:

try
{
// Function body
}
catch (std::exception& ex)
{
throw MfcStdException::Create(ex);
}
catch (_com_error& ex)
{
throw MfcComException::Create(ex);
}
... // More clauses, but catch (...) is still dangerous

Macros can help here. Unfortunately, you can't do the above in some central
location, because MFC contains numerous occurrences of things like:

TRY
{
// Call your code
}
CATCH_ALL(e)
{
// Clean up and return FALSE.
}

Overriding (say) WindowProc and guarding it as above won't help you, because
the non-MFC exceptions will skip right over MFC's CATCH_ALL clauses, which
are intended to catch all exceptions. To be safe, all functions that can
potentially exit to MFC via a non-MFC exception must be guarded by a
translating try/catch wrapper.

>It would be nice if C++ had
>some sort of official way to map SEGV (and others) to C++ exceptions.

But it would be nicer if C++ outright forbid that mapping, since the intent
is for it not to be done (see Stroustrup's books). The C++ Standard allows
it only through the loophole of undefined behavior, upon which it imposes no
requirements.

>You can set up a handler (via SetUnhandledExceptionFilter) where you
>can throw an appropriate C++ exception for each win32 exception. You
>have to take into account folks that might have called signal().

The problem with translating SEs into C++ exceptions is that you have to
write a catch(...) that is intended to catch only "true" C++ exceptions as:

catch (se_t) { throw; }
catch (...) { ... }

This is tedious and error-prone. Translating SEs into C++ exceptions with
the help of _set_se_translator really isn't much help. It's still hard to
use correctly, and it's still easy to catch things you really don't want in
catch(...). It's much better to keep OS-specific things like SEs and signals
separate from C++ exceptions. Instead of homogenizing them in catch(...), VC
should fix catch(...) to catch C++ exceptions only, deprecate
_set_se_translator, and introduce a new keyword, such as __catch_se, that
can be used with try/catch and is dedicated to catching SEs. __try/__except
would remain available for those who need to deal with SEs at the OS level.

--
Doug Harrison
dHar...@worldnet.att.net


0 nuovi messaggi