Is there a favored idiom for mimicing Java's t

2019-03-15 07:39发布

Been doing Java for number of years so haven't been tracking C++. Has finally clause been added to C++ exception handling in the language definition?

Is there a favored idiom that mimics Java's try/finally?

Am also bothered that C++ doesn't have an ultimate super type for all possible exceptions that could be thrown - like Java's Throwable class.

I can write:

try {
  // do something
} catch(...) {
  // alas, can't examine the exception
  // can only do cleanup code and perhaps rethrow, ala:
  throw;
}

ADDENDUM EDIT:

I ended up accepting the answer that had the most up votes, i.e., use destructors to do cleanup. Of course, from my own comments, it is clear I don't entirely agree with that. However, C++ is what it is and so in the application endeavor I have in mind, I'm going to more or less strive to adhere to common community practice. I'll use template classes to wrap resources that don't already have a class destructor (i.e., C library resources), thus bestowing on them destructor semantics.

NEW ADDENDUM EDIT:

Hmm, instead of finally then a closure feature perhaps? A closure combined with ScopeGuard approach (see one of the answers below) would be a way to accomplish cleanup with arbitrary actions and access to the cleanup code's outer scope context. Cleanup could be done in the idiom fashion that is seen in Ruby programming where they supply cleanup blocks when a resource is being opened. Isn't a closure feature being considered for C++?

15条回答
太酷不给撩
2楼-- · 2019-03-15 08:11

C++ destructors make finally redundant. You can get the same effect by moving the cleanup code from finally to corresponding destructors.

查看更多
放我归山
3楼-- · 2019-03-15 08:13

C++'s answer is RAII: The object's destructor will be executed when they go out of scope. Whether by a return, by an exception or whatever. If you handle the exception somewhere else, you can be sure all objects from the called function down to your handler will be properly destructed by having their destructor called. They will clean up for you.

Read http://en.wikipedia.org/wiki/Resource_acquisition_is_initialization

查看更多
别忘想泡老子
4楼-- · 2019-03-15 08:14

Cleanup functions, themselves, are thoroughly lame. They have low cohesion, in that they are expected to perform a series of activities only related in when they happen. They have high coupling, in that they need to have their internals modified when the functions that actually do something are changed. Because of this, they're error-prone.

The try...finally construct is a framework for cleanup functions. It is a language-encouraged way to write lousy code. Moreover, since it encourages writing the same cleanup code over and over, it undermines the DRY principle.

The C++ way is far preferable for these purposes. The cleanup code for a resource is written precisely once, in the destructor. It's in the same place as the rest of the code for that resource, and therefore has good cohesiveness. The cleanup code doesn't have to be put into unrelated modules, and therefore this cuts down on coupling. It is written precisely once, when well designed.

Moreover, the C++ way is much more uniform. C++, with the smart pointer additions, handles all sorts of resources in the same way, while Java handles memory well and provides inadequate constructs to release other resources.

There are plenty of problems with C++, but this isn't one of them. There are ways in which Java is better than C++, but this isn't one of them.

Java would be much better off with a way to implement RAII instead of try...finally.

查看更多
走好不送
5楼-- · 2019-03-15 08:15

No finally has not been added to C++, nor is it likely to ever be added.

The way C++ uses constructor/destructor makes the need for finally unnecessary.
If you are using catch(...) to cleanup then you are not using C++ properly. The cleanup code should all be in the destructor.

Though it is not a requirement to use it C++ does have a std::exception.
Forcing developers to derive from a specific class to use exception goes against the keep it simple philosophy of C++. Its also why we don't require all classes to derive from Object.

Read: Does C++ support 'finally' blocks? (And what's this 'RAII' I keep hearing about?)

The use of finally is more error prone than destructors to do clean up.
This is because you are forcing the user of the object to do clean up rather than the designer/implementer of the class.

查看更多
欢心
6楼-- · 2019-03-15 08:15

Regarding your addendum-edit, yes closures are being considered for C++0x. They can be used with RAII scoped guards to provide an easy to use solution, check Pizer's weblog. They can also be used to mimic try-finally, see this answer ; but is this really a good idea ? .

查看更多
可以哭但决不认输i
7楼-- · 2019-03-15 08:18

An Example of how difficult it is to use finally correctly.

Open and closing two files.
Where you want to guarantee that the file is closed correctly.
Waiting for the GC is not an option as the files may be re-used.

In C++

void foo()
{
    std::ifstream    data("plop");
    std::ofstream    output("plep");

    // DO STUFF
    // Files closed auto-magically
}

In a language with no destructors but has a finally clause.

void foo()
{
    File            data("plop");
    File            output("plep");

    try
    {
        // DO STUFF
    }
    finally
    {
        // Must guarantee that both files are closed.
        try {data.close();}  catch(Throwable e){/*Ignore*/}
        try {output.close();}catch(Throwable e){/*Ignore*/}
    }
}

This is a simple example and already the code is getting convoluted. Here we are only trying to marshal 2 simple resources. But as the number of resources that need to be managed increases and/or their complexity increases the use of a finally block becomes harder and harder to use correctly in the presence of exceptions.

The use of finally moves responsibility for correct usage onto the user of an object. By using constructor/destructor mechanism provided by C++ you move the responsibility of correct usage to the designer/implementer of the class. This is inheritanly safer as the designer only needs to do it correctly once at the class level (rather than have different users try and do it correctly in different ways).

查看更多
登录 后发表回答