Using std::bad_alloc for C pointers
I'm using a library written in C in a C++ project.
I'd like to use C++ exceptions to handle C errors. In particular, it would be nice to have an except开发者_StackOverflowion thrown if an allocation fails.
I can do this in constructors of classes which hold C-style pointers to C structs :
if (c_object == NULL)
throw std::bad_alloc();
But if the class is responsible for several C objects they are no ways of free-ing all already allocated pointers since the destructor isn't called.
I have a feeling I could use smart-pointers, but I don't have much experience with them. What's more, I have to have access to the original C pointers to use the C api properly.
Is there an elegant solution to this ?
It has been already mentioned in the comments, I merely repeat it as an answer:
But if the class is responsible for several C objects they are no ways of free-ing all already allocated pointers since the destructor isn't called.
That is correct. Because of this and the single-responsibility principle, each C++ class manages at most one unmanaged resource ("C object" in your case). And those classes that do manage a resource do absolutely nothing else.
If you use a smart pointer, you do exactly that: the smart pointer class manages access to a single type of resource, namely, heap objects usually allocated with new
(the latter can be customized). If that would help you, feel free to use a smart pointer, which is completely fine, but never write a class that manages more than one raw resource.
You can store each pointer in a smart pointer like shared_ptr
. Those also accept (optionally) a pointer to a deallocation function.
To throw exceptions, you can wrap each allocation function.
//the api functions
Foo* CreateFoo(Bar);
void DestroyFoo(const Foo*);
//wrapped with
boost::shared_ptr<Foo> CppCreateFoo(Bar bar)
{
boost::shared_ptr<Foo> new_foo(CreateFoo(bar), &DestroyFoo);
if (!new_foo) {
throw std::bad_alloc();
}
return new_foo;
}
//underlying pointer accessed with
boost::shared_ptr<Foo> smart_foo_ptr = CppCreateFoo(bar);
UseFooPtr(smart_foo_pointer.get());
Why can't you use try -catch
block in constructor ?
A::A() : c_object(0), c1_object(0), c2_object(0)
{
try
{
c_object = getCObject();
if (!c_object)
throw std::bad_alloc();
c1_object = getCObject1();
if (!c1_ojbect)
throw std::bad_alloc();
//.....
}
catch (std::bad_alloc& )
{
if (c_object)
releasCObjectMemory(c_object);
if (c1_object)
releasCObjectMemory(c1_object);
//....
throw;
}
}
I think you are trying to trivially achieve what basically is NOT trivially achievable. In any case, I think it's best to decide between the following two approaches
- for each struct, write a C++ wrapper
- follow C approach without exceptions (as is now)
I don't think you can achieve the effect of 1 with no effort of option 2 :)
HTH
精彩评论