Is it possible to catch an exception raised by a member variable?

A

Angus

Hello

I have a class I am using which raises an exception in its constructor
if certain things aren't in place. I can easily create the situation
where an exception is raised.

If I use the create a member variable in a class using this class then
how do I catch the exception?

For now I have defined a member function as a pointer and in my
constructor in my class using the class which raises the exception, I
do a try catch block and do a new object. That works. But is it
possible to do a similar thing using a member variable?

Angus
 
V

Victor Bazarov

Angus said:
I have a class I am using which raises an exception in its constructor
if certain things aren't in place. I can easily create the situation
where an exception is raised.

OK. So creation of a subobject fails. Quite common.
If I use the create a member variable in a class using this class then
how do I catch the exception?

The exception has to be caught by the code that instantiates (or rather
tries to instantiate) the host object.
For now I have defined a member function as a pointer and in my
constructor in my class using the class which raises the exception, I
do a try catch block and do a new object. That works. But is it
possible to do a similar thing using a member variable?

Yes, but if your member fails to be constructed, can your object still
exist and function? If it can, you should use the pointer solution,
which apparently works. If your object cannot exist and function with
some part of it missing, then you should do nothing, the constructor
of the entire object will throw (because some part of it throws), and
the exception has to be caught outside.

V
 
C

Chris ( Val )

OK. So creation of a subobject fails. Quite common.


The exception has to be caught by the code that instantiates (or rather
tries to instantiate) the host object.


Yes, but if your member fails to be constructed, can your object still
exist and function? If it can, you should use the pointer solution,
which apparently works. If your object cannot exist and function with
some part of it missing, then you should do nothing, the constructor
of the entire object will throw (because some part of it throws), and
the exception has to be caught outside.

Hi Victor, I think it can still be created and exist under certain
circumstances:

For example:

You could use a function try block, which will then catch the
exception
in the initialiser list, prior to executing the body of the
constructor,
therefore the object is still alive to an extent, as it is still in
the
process of being created.

The try block itself becomes the constructor body, with the catch
block
immediately following it. A function try block also allows us to throw
out of the constructor with a different exception object than what was
initially caught.

Cheers,
Chris Val
 
J

Jonathan Lane

Hi Victor, I think it can still be created and exist under certain
circumstances:

For example:

You could use a function try block, which will then catch the
exception
in the initialiser list, prior to executing the body of the
constructor,
therefore the object is still alive to an extent, as it is still in
the
process of being created.

The try block itself becomes the constructor body, with the catch
block
immediately following it. A function try block also allows us to throw
out of the constructor with a different exception object than what was
initially caught.

Cheers,
Chris Val

I think the problem with this is that yes you can use the function
catch block but what can you do if it throws. The object doesn't exist
until it has completely finished construction. If you want to be able
to use the object without this member then it needs to be a pointer
with a try catch around it in the constructor body. That way you can
complete the constructor and just not use that member.
If you leave it as a non-pointer then all you can achieve in the
function catch is to translate the exception. The object still doesn't
exist because the constructor didn't complete. The stack will unwind
and the bits that were already constructed will be destructed. i.e.
it's a non object and can't be used.

Depends on what the poster wants to be able to do if a sub object
fails to construct. Of course, I may be mistaken I'm a bit foggy on
the whole functional try/catch stuff, it doesn't come up often for me.
 
J

James Kanze

I think it can still be created and exist under certain
circumstances:

Not if the construction of a sub-object fails.
For example:
You could use a function try block, which will then catch the
exception in the initialiser list, prior to executing the body
of the constructor, therefore the object is still alive to an
extent, as it is still in the process of being created.
The try block itself becomes the constructor body, with the
catch block immediately following it. A function try block
also allows us to throw out of the constructor with a
different exception object than what was initially caught.

But you still don't have an object. You can use function try
blocks to remap the exception, or to treat it as a fatal error
(e.g. by calling abort or exit), but you cannot return normally
from the constructor, and the object that was being constructed
will not exist.
 
C

Chris ( Val )

Not if the construction of a sub-object fails.


But you still don't have an object. You can use function try
blocks to remap the exception, or to treat it as a fatal error
(e.g. by calling abort or exit), but you cannot return normally
from the constructor, and the object that was being constructed
will not exist.

Hi James,

I have produced a crude example that will attempt to
prove otherwise:

# include <iostream>
# include <string>
# include <exception>

struct DataSource {
DataSource( std::string ds )
{
if( ds != "Oracle.driver.foo" )
throw "Could not connect to database";
}
};

class Base
{
private:
DataSource Ds;
public:
Base( std::string );
~Base() { std::cout << "Destructing now...\n"; }
void Print()
{ std::cout << "I am still alive - Please try again.\n"; }
};

Base::Base( std::string ds )
try // function-try block
: Ds( ds ) {}
catch( const char* msg ) {
std::cout << "Exception Caught: \"" << msg << "\"" << '\n';
throw std::exception();
}

int main()
{
Base* B;

try {
B = new Base( "Oracle.driver.bar" );
}
catch( const std::exception& e )
{
B->Print();
delete B;
}

std::cin.get();
return 0;
}

I am interested to hear your, and the groups
thoughts on the validity of such a construct.

:)

Cheers,
Chris Val
 
P

Pete Becker

int main()
{
Base* B;

try {
B = new Base( "Oracle.driver.bar" );
}
catch( const std::exception& e )
{
B->Print();
delete B;
}

std::cin.get();
return 0;
}

I am interested to hear your, and the groups
thoughts on the validity of such a construct.

It really doesn't show anything. Replace the "B = new ..." with "throw
std::exception();" and you'll probably get the same result. Calling
member functions on uninitialized pointers produces undefined behavior,
so anything you see is as valid as anything else.
 
C

Chris ( Val )

It really doesn't show anything. Replace the "B = new ..." with "throw
std::exception();" and you'll probably get the same result. Calling
member functions on uninitialized pointers produces undefined behavior,
so anything you see is as valid as anything else.

I tried a non pointer version, and the results are the same.

What I am curious about is at what point does the object actually
cease to exist? (which scope?)

Is it not possible for it to even be partially constucted to
report such information back?

I know UB can mean anything can happen, but I'm curious.
Its a powerful drug that UB, it can get you hooked line
and sinker :)

Thanks for the feedback,
Chris Val
 
V

Victor Bazarov

Chris said:
I tried a non pointer version, and the results are the same.

What I am curious about is at what point does the object actually
cease to exist? (which scope?)

The pointer does not cease to exist. The object, however, is not
created. So, whatever address the pointer contains in the 'catch'
block, is not the address of a valid object. That makes the pointer
_invalid_.
Is it not possible for it to even be partially constucted to
report such information back?

Partially constructed means not fully constructed, doesn't it? In
my book you cannot use any partially constructed object except to
take its address.
I know UB can mean anything can happen, but I'm curious.
Its a powerful drug that UB, it can get you hooked line
and sinker :)

Yep.

V
 
C

Chris ( Val )

Chris ( Val ) wrote:
[snip]
What I am curious about is at what point does the object actually
cease to exist? (which scope?)

The pointer does not cease to exist. The object, however, is not
created. So, whatever address the pointer contains in the 'catch'
block, is not the address of a valid object. That makes the pointer
_invalid_.
Is it not possible for it to even be partially constucted to
report such information back?

Partially constructed means not fully constructed, doesn't it?
Yes.

In my book you cannot use any partially constructed object except to
take its address.

Thats fine, but I thought there may be a chance that the
object could be stopped in its tracs, and somehow completed.

But having a re-think about it doesn't seem possible, well
at least I couldn't find any supporting material without
spending hours digging deep into the standard :)

Thanks again,
Chris Val
 
P

Pete Becker

What I am curious about is at what point does the object actually
cease to exist? (which scope?)

Well, formally, it never existed, because its constructor didn't run to
completion. Mechanically, what happens is that when the exception
escapes from the try block (or, more generally, when an exception
escapes from a constructor), the destructors for the various subobjects
that have been constructed are run. In addition, if the object was
being created with new, the compiler calls the corresponding operator
delete to release the memory. It's up to the compiler to get all that
logic right.

struct OK
{
~OK() { std::cout << "destroying an OK object\n"; }
};

struct Throws
{
Throws { throw 1; }
};

struct Complicated: OK, Throws, OK
{
~Complicated() { std::cout << "destroying a Complicated object\n"; }
};

Your compiler might warn you that you can't call members of OK, because
their names are ambiguous. Ignore that: it's not relevant here.

Try creating an object of type Complicated. (I haven't compiled this
code, but it ought to be more or less okay).
 
P

Pete Becker

Well, formally, it never existed, because its constructor didn't run to
completion. Mechanically, what happens is that when the exception
escapes from the try block

Sorry, I suspect that should be "from the catch clause". I'm a bit
pressed for time this morning, so I haven't looked it up.
 
J

James Kanze

On Sep 28, 7:03 pm, James Kanze <[email protected]> wrote:

[...]
I have produced a crude example that will attempt to
prove otherwise:
# include <iostream>
# include <string>
# include <exception>
struct DataSource {
DataSource( std::string ds )
{
if( ds != "Oracle.driver.foo" )
throw "Could not connect to database";
}
};
class Base
{
private:
DataSource Ds;
public:
Base( std::string );
~Base() { std::cout << "Destructing now...\n"; }
void Print()
{ std::cout << "I am still alive - Please try again.\n"; }
};
Base::Base( std::string ds )
try // function-try block
: Ds( ds ) {}
catch( const char* msg ) {
std::cout << "Exception Caught: \"" << msg << "\"" << '\n';
throw std::exception();
}
int main()
{
Base* B;
try {
B = new Base( "Oracle.driver.bar" );
}
catch( const std::exception& e )
{
B->Print();

This is undefined behavior, since it accesses an uninitialized
pointer. If you get here, the assign in the try block has never
occured (and there is no Base object).
delete B;
}
std::cin.get();
return 0;
}
I am interested to hear your, and the groups
thoughts on the validity of such a construct.

Totally invalide.
 
J

James Kanze

I tried a non pointer version, and the results are the same.

Could you show it. If you replace the line with new Base...,
with something like:

Base b( "Oracle.driver.bar" ) ;

then b isn't even in scope in the catch block, and cannot be
accessd.
What I am curious about is at what point does the object actually
cease to exist? (which scope?)

Which object. The object whose destructor exits via an
exception never begins to exist, so the question of when it
ceases to exist is moot.
Is it not possible for it to even be partially constucted to
report such information back?

No. Or rather, it can put information in the exception, which
will propagate up. But if a constructor exits because of an
exception, all fully constructed sub-objects are immediately
destructed, and if the constructor was called as part of a new
expression, the allocated memory is immediately freed.
 
C

Chris ( Val )

[...]




But you still don't have an object. You can use function try
blocks to remap the exception, or to treat it as a fatal error
(e.g. by calling abort or exit), but you cannot return normally
from the constructor, and the object that was being constructed
will not exist.
I have produced a crude example that will attempt to
prove otherwise:
# include <iostream>
# include <string>
# include <exception>
struct DataSource {
DataSource( std::string ds )
{
if( ds != "Oracle.driver.foo" )
throw "Could not connect to database";
}
};
class Base
{
private:
DataSource Ds;
public:
Base( std::string );
~Base() { std::cout << "Destructing now...\n"; }
void Print()
{ std::cout << "I am still alive - Please try again.\n"; }
};
Base::Base( std::string ds )
try // function-try block
: Ds( ds ) {}
catch( const char* msg ) {
std::cout << "Exception Caught: \"" << msg << "\"" << '\n';
throw std::exception();
}
int main()
{
Base* B;
try {
B = new Base( "Oracle.driver.bar" );
}
catch( const std::exception& e )
{
B->Print();

This is undefined behavior, since it accesses an uninitialized
pointer. If you get here, the assign in the try block has never
occured (and there is no Base object).
delete B;
}
std::cin.get();
return 0;
}
I am interested to hear your, and the groups
thoughts on the validity of such a construct.

Totally invalide.

The non-pointer version that I spoke of was
totally wrong. I thought about it after I
posted, amd realised I was just assigning
a new object in the catch block. It was late
and I totally confused myself :)

Thanks to both you and Peter for clarifying it.

Cheers,
Chris Val
 
C

Chris ( Val )

Sorry, I suspect that should be "from the catch clause". I'm a bit
pressed for time this morning, so I haven't looked it up.

No problem at all, I appreciate the help and example.

Thanks,
Chris Val
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top