开发者

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

  1. for each struct, write a C++ wrapper
  2. 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜