Stefan said:
Wrapper classes introduce more code.
I'd rate this as FUD. I just tested the following two translation units
with gcc on a StrongARM (I currently don't have access to gcc on an
Intel machine):
| // file tst1.cpp
| extern void f(int* i);
| void g() {
| int* i = new int(10);
| try { f(i); }
| catch ( ... ) {}
| delete i;
| }
This is as close at "finally" as possible: the try/catch is necessary
or some equivalent is necessary for the finally-clause, too. However,
deleting and rethrowing in the catch-clause would increase the code
even more (see tst3.cpp below).
| // file tst2.cpp
| extern void f(int* i);
| struct ptr {
| ptr(int* p): mp(p) {}
| ~ptr() { delete mp; }
| int* mp;
| };
| void g() {
| ptr p(new int(10));
| f(p.mp);
| }
It is admittedly more code but it can be placed into a header and
reused
in multiple places.
| // file tst3.cpp
| extern void f(int* i);
| void g() {
| int* i = new int(10);
| try { f(i); delete i; }
| catch ( ... ) { delete i; throw;}
| }
This is the manual approach without finally.
| // file tst4.cpp
| extern void f(int* i);
| template <typename T>
| struct ptr {
| ptr(T* p): mp(p) {}
| ~ptr() { delete mp; }
| T* get() { return mp; }
| private:
| ptr(ptr const&);
| void operator= (T const&);
| T* mp;
| };
| void g() {
| ptr p(new int(10));
| f(p.get());
| }
.... and I thought it is instructive to put this follow-blown version
using templates into it, too.
Compiled with "g++ -O4 -c tst*.cpp" I get the following:
| size *.o
| text data bss dec hex filename
| 172 16 0 188 bc tst1.o
| 180 6 0 186 ba tst2.o
| 228 16 0 244 f4 tst3.o
| 180 6 0 186 ba tst4.o
(I couldn't paste the results as they are on my PDA which is not
connected
to the machine I'm typing at).
Although the memory wasted by the non-automatic version is not too bad,
the automatic release is shorter, at minimum two bytes - not much but
you complained about use less code. Of course, if you want the correct
semantics, i.e. the exception shall not be swallowed, you have no
choice but go with automatic resource release if you don't want to
waste memory...
I would like to use less code. I also
think it is a workaround and not a structural solution.
I disagree: the idiom of handling resources is essential to effective
C++ programming.
The above would simply move the exception handling and my finally problem
to a different place but it would still be present.
Where does the resource management class need a "finally"? All
exception
handling code is entirely generated by the compiler which will probably
generate something akin to finally but there is no need to care at all.
Also, resource management is centralized in one place. There is no
chance
of forgetting to clean up allocated resource (well, you can have a
plain
new but you shouldn't) because the finally clause is omitted. The code
is
not littered with clean-up code which is irrelevant to the actual
business
logic.
I like it that you as
a user of the class don't have to deal with it anymore, but that is more
visual/convenience.
I disagree. Actually, if you are ever doing template programming you
will
appreciate that you don't have to know how to clean-up the objects you
are handling. You don't even need to care whether they need clean-up:
it
is the object's business, not yours. It is a logical step toward
encapsulation.