Reputation: 17148
in the newest The C++ Programming language book, Bjarne presents an alternative to an orthodox error handling, that is to use exceptions. This is in chapter 13.3.1, and he writes:
void test()
// handle undiciplined resource acquisition
// demonstrate that arbitrary actions are possible
{
int* p = new int{7}; // probably should use a unique_ptr (§5.2)
int* buf = (int*)malloc(100*sizeof(int)); // C-style allocation
auto act1 = finally([&]{ delete p;
free(buf); // C-style deallocation
cout<< "Goodby, Cruel world!\n";
}
);
int var = 0;
cout << "var = " << var << '\n';
// nested block:
{
var = 1;
auto act2 = finally([&]{ cout<< "finally!\n"; var=7; });
cout << "var = " << var << '\n';
} // act2 is invoked here
cout << "var = " << var << '\n';
}// act1 is invoked here
Although I understand what he is trying to explain and what this code is supposed to achieve, I have problem with believing that this fragment is leek free:
> 1. int* p = new int{7}; // probably should use a unique_ptr (§5.2)
> 2. int* buf = (int*)malloc(100*sizeof(int)); // C-style allocation
>
>
> 3. auto act1 = finally([&]{ delete p;
> free(buf); // C-style deallocation
> cout<< "Goodby, Cruel world!\n";
> }
> );
Why? Because if in line two (2) we get exception thrown (assuming that there isn't call to a malloc but to a function that can actually throw, as I believe the concept that Bjarne is trying to explain is to use the finally construct and the malloc call here is irrelevant and accidental and could be replaced by any call), then if two throws then 3 will never be reached and we have resource leek from 1. Am I correct?
Upvotes: 0
Views: 113
Reputation: 16188
Basically what is happening in the above code segment is:
int* p = new int{7}; // probably should use a unique_ptr
int* buf = (int*)malloc(100*sizeof(int)); // C-style allocation
Memory is allocated both via C++ new
and C
malloc. Neither of the pointer are managed, and if any code at this point were to throw then memory would be leaked. However, note that malloc
does not throw so in isolation this code is safe.
http://en.cppreference.com/w/cpp/memory/c/malloc
auto act1 = finally([&]{ delete p;
free(buf); // C-style deallocation
cout<< "Goodby, Cruel world!\n";
}
);
In this code an RAII type is returned from the finally function. Which will execute the callable parameter when act1
is destroyed (either on exception or on leaving this scope).
Because this directly follows the malloc
we have now ensured that the memory can not leak.
The following code however would be unsafe:
int* p = new int{7}; // probably should use a unique_ptr
int* buf = (int*)malloc(100*sizeof(int)); // C-style allocation
throwing_function();
auto act1 = finally([&]{ delete p;
free(buf); // C-style deallocation
cout<< "Goodby, Cruel world!\n";
}
);
However Bjarne comment is spot on, just use a std::unique_ptr
.
EDIT:
A use of finally:
database_handle dh1;
dh1.do("action...");
finally([&]{
if(!dh1.success()) {
dh1.rollback();
}
);
Upvotes: 1