I have an API written in C, which produces a result by returning a pointer to allocated memory.
For using it with C++ (C++11) I've wrapped the function calls in objects, which keep the result in a std::shared_ptr
. So far so good.
However, the C library features two functions for every operation. One produces possibly an error, the other never. Let's call them
some_pod * do_it_with_error(Parameter ..., Error **)
and
some_pod * do_it_without_error(Parameter ...)
I can pass in the address of an Error *
pointer to the first function and if there's an error it won't be NULL
afterwards.
For solving this I thought of two different implementations.
First, I could SFINAE for choosing between the with_error
and without_error
functions, like so:
template<typename NoThrow = void>
struct do_it {
public:
void operator()(...)
{
Error * error = NULL;
m_result = std::shared_ptr<some_pod>(do_it_with_error(..., &error));
if (error) {
throw(MyExceptionWithError(error));
}
}
private:
std::shared_ptr<some_pod> m_result;
};
template<>
class do_it<std::nothrow_t> {
public:
void operator()(...) noexcept
{
if (! m_result) {
m_result = std::shared_ptr<some_pod>(do_it_without_error(...));
}
}
private:
std::shared_ptr<some_pod> m_result;
};
Usage:
do_it<> di_error;
try {
di_error(...); // might throw
} catch (...) {}
do_it<std::nothrow_t> di_no_error;
di_no_error(...); // won't throw for sure
However, since the result is wrapped in a std::shared_ptr
there will also be
a get()
method:
const std::shared_ptr<some_pod> & get(void) { return m_result; }
For error checking I could just implement a another method check
.
The default implementation would now look like this:
struct do_it {
public:
// will never throw
const std::shared_ptr<some_pod> &
get(void) noexcept
{
if (! m_result) {
m_result = std::shared_ptr<some_pod>(do_it_without_error(...));
}
return m_result;
}
// might throw
do_it &
check(void)
{
if (! m_result) {
Error * error = NULL;
m_result = std::shared_ptr<some_pod>(do_it_with_error(..., &error));
if (error) {
throw ...;
}
}
return *this;
}
private:
std::shared_ptr<some_pod> m_result;
};
Usage:
do_it di_error;
try {
auto result = di_error.check().get();
} catch (...) {}
do_it di_no_error;
di_no_error.get();
So, both implementations seem to be equally good (or bad) to me.
How could I decide which one to use.
What are the Pros and Cons?
shared_ptr
! If it's a C API, the object it returns was allocated withmalloc
and therefore must be deleted withfree
. If you justdelete
is asshared_ptr
does by default, it will explode on some platforms.shared_ptr
can get a custom deleter, pass it one that releases usingfree
.