Jump to content
  • Advertisement
Sign in to follow this  
Promit

RAII and try-catch scoping irritation

This topic is 4838 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

There's a little something about RAII that's bothering me. Let's take an RaiiObject whose constructor can throw an exception. Consider the following code
void Foo()
{
    try
    {
        RaiiObject ro( "FileName.file" );

        //do stuff with ro, maybe
    }
    catch( std::runtime_error ex )
    {
        std::cout << "An exception occurred: " << ex.what() << std::endl;
        throw ex;
    }

    //now suppose I want to do things with ro here?
    //I can't, because ro is out of scope!
}

So my options are either to make ro a pointer and use new, or put the rest of the function in the try {} section. Suppose I don't want to catch exceptions in the rest of the code though. Then I have to make ro a pointer. These don't seem like great options to me. Right now I can deal with things fairly well by inheriting from std::runtime_error and throwing and catching more specific exceptions. Then the entire body of the function resides within the try block, but I don't necessarily have to catch every exception it causes. Am I missing something, or is this just The Way Things Are?

Share this post


Link to post
Share on other sites
Advertisement
I'm confused why you think using new and getting a pointer means you don't have to catch the exception.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
I'm confused why you think using new and getting a pointer means you don't have to catch the exception.

I think his point was that you could define the pointer outside the try-catch block, then initialize it inside, thus allowing you to use different error handling procedures for the creation of the object and the use of the object.

Share this post


Link to post
Share on other sites
I'm still confused. If you declare it as an auto variable and the constructor throws, you generate an exception. If you declare at as pointer, new it and the constructor throws you generate the exact same exception. Now you have to delete it at the end *and* do all the same exception handling.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
If you declare at as pointer, new it and the constructor throws you generate the exact same exception. Now you have to delete it at the end *and* do all the same exception handling.


Exactly. Making it a pointer practically defeats the purpose of RAII to begin with. But that's the only way to scope it outside the try-catch block. That's what's bothering me. I can't access the object outside of the try-catch, so I can't use it after exiting the try.

Here, this is what I mean by using a pointer:

void Foo()
{
RaiiObj* ro;
try
{
ro = new RaiiObj( "FileName.File" );
...
}
catch( std::runtime_error ex )
{
...
}

//do more with ro here
delete ro; // this sucks
}


Share this post


Link to post
Share on other sites
I think what he's getting at is something like this:

{
Foo f;
try
{
f.Bar();
}
catch(FooException e)
{
// handle things one way
}

try
{
f.Baz();
}
catch(FooException e)
{
// handle things another way
}


...which works until your first try-block is trying to construct the variable.

Share this post


Link to post
Share on other sites
Quote:
Original post by Promit
There's a little something about RAII that's bothering me. Let's take an RaiiObject whose constructor can throw an exception. Consider the following code
*** Source Snippet Removed ***
So my options are either to make ro a pointer and use new, or put the rest of the function in the try {} section. Suppose I don't want to catch exceptions in the rest of the code though. Then I have to make ro a pointer. These don't seem like great options to me. Right now I can deal with things fairly well by inheriting from std::runtime_error and throwing and catching more specific exceptions. Then the entire body of the function resides within the try block, but I don't necessarily have to catch every exception it causes. Am I missing something, or is this just The Way Things Are?

That's why you put the code that deals with the object also inside the try block rather than outside.

Share this post


Link to post
Share on other sites
So in short, there's no particularly good way to scope the RAII object outside of the try?

Share this post


Link to post
Share on other sites
Generally, I wouldn't catch at that level, but at the next highest level:

try {
Foo();
} catch(FileNotFoundException& ex) {
...
}


Assuming that's not an option, use a copy:

void Foo() {
RaiiObject ro1;
try {
RaiiObject ro2(...);
ro1 = ro2;
} catch(FileNotFoundException& ex) {
...
}
}


Of course, even that's not a perfect solution.

Share this post


Link to post
Share on other sites
Oh god, it just hit me like a ton of bricks.

Accessing an RAII object outside of the try block only makes sense if the catch block always causes execution to leave the function, either by returning or by throwing. If the catch allowed execution to continue in the function, and the rest of the function attempted to use that RAII object...


So, yeah, I'm stupid.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!