C++ classes provide RAII idiom. Therefore you don't have to care about exceptions:
void function()
{
// The memory will be freed automatically on function exit
std::vector<int> vector(1000);
// Do some work
}
But if you have (for some reasons) to use some pure C API, you have either to create C++ wrappers around it or to use try/catch blocks
void function()
{
int *arr = (int*)malloc(1000*sizeof(int));
if (!arr) { throw "cannot malloc"; }
try
{
// Do some work
}
catch (...)
{
free(arr); // Free memory in case of exception
throw; // Rethrow the exception
}
// Free memory in case of success
free(arr);
}
Even if you use C++ classes with RAII idiom, sometimes you have to write a code with strong exception-safety guaranty:
void function(std::vector<const char*> &vector)
{
vector.push_back("hello");
try
{
// Do some work
vector.push_back("world");
try
{
// Do other work
}
catch (...)
{
vector.pop_back(); // Undo vector.push_back("world")
throw; // Rethrow the exception
}
}
catch (...)
{
vector.pop_back(); // Undo vector.push_back("hello");
throw; // Rethrow the exception
}
}
But these constructions are quite bulky.
Is there any way to force to run some cleanup code at function exit? Something similar to atexit
, but in a function scope...
Is there any way to run some rollback code in case of exception without using nested try/catch blocks?
I would like to have some operators or functions that would work like this:
void function(std::vector<const char*> &vector)
{
int *arr = malloc(1000*sizeof(int));
onexit { free(arr); }
vector.push_back("hello");
onexception { vector.pop_back(); }
// Do some work
vector.push_back("world");
onexception { vector.pop_back(); }
// Do other work
}
If it is possible to create such functions, are there any reasons to avoid using them? Are there such constructs in other programming languages?
malloc
? – Platermalloc
is just a simple example, it could be any function from pure C library that doesn't have C++ alternative. – Simsarpush_back
s on a copy of the original vector and just swap the two when the whole transaction has been completed? – Emlynstd::vector
may be unacceptable due to performance limitations. The code in my question is just a simple example. Sometimes it is impossible to use copy-and-swap idiom at all. – Simsar