Использование std :: bad_alloc для указателей на C - PullRequest
0 голосов
/ 18 февраля 2011

Я использую библиотеку, написанную на C, в проекте C ++.

Я бы хотел использовать исключения C ++ для обработки ошибок C.В частности, было бы неплохо создать исключение в случае сбоя выделения.

Я могу сделать это в конструкторах классов, которые содержат указатели в стиле C на структуры C:

if (c_object == NULL)
    throw std::bad_alloc();

Но если класс отвечает за несколько объектов C, они не могут освободить все уже выделенные указатели, поскольку деструктор не вызывается.

У меня такое чувство, что я мог бы использовать smart-указатели, но я нене имеет большого опыта с ними.Более того, у меня должен быть доступ к оригинальным указателям на C, чтобы правильно использовать C api.

Есть ли элегантное решение для этого?

Ответы [ 4 ]

3 голосов
/ 18 февраля 2011

Это уже упоминалось в комментариях, я просто повторяю это как ответ:

Но если класс отвечает за несколько объектов C, они не являются способами освобождения всех уже выделенныхуказатели, поскольку деструктор не вызывается.

Это правильно.Из-за этого и принципа единственной ответственности каждый класс C ++ управляет не более чем одним неуправляемым ресурсом («объект C» в вашем случае).И те классы, которые действительно управляют ресурсом, абсолютно ничего не делают.

Если вы используете умный указатель, вы делаете именно это: класс умного указателя управляет доступом к одному типу ресурса, а именно объектам кучи, обычно выделяемымс new (последний можно настроить).Если это поможет вам, не стесняйтесь использовать умный указатель, что вполне нормально, но никогда не пишите класс, который управляет более чем одним необработанным ресурсом.

3 голосов
/ 18 февраля 2011

Вы можете сохранить каждый указатель в интеллектуальном указателе, например shared_ptr.Они также принимают (опционально) указатель на функцию освобождения.

Чтобы генерировать исключения, вы можете обернуть каждую функцию выделения.

//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());
2 голосов
/ 18 февраля 2011

Почему вы не можете использовать try -catch блок в конструкторе?

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;
    }
}
1 голос
/ 18 февраля 2011

Я думаю, что вы пытаетесь тривиально достичь того, что в принципе НЕ тривиально достижимо.В любом случае, я думаю, что лучше выбрать между двумя подходами

  1. для каждой структуры, написать оболочку C ++
  2. следовать подходу C без исключений (как сейчас)

Я не думаю, что вы можете достичь эффекта 1 без усилий варианта 2 :)

HTH

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...