Можно ли использовать умные указатели C ++ вместе с malloc C? - PullRequest
20 голосов
/ 13 августа 2010

В моем коде все еще используется malloc вместо new.Причина в том, что я боюсь использовать new, потому что он генерирует исключение, а не возвращает NULL, который я легко могу проверить.Завершение каждого звонка на new в try{}catch(){} также выглядит не очень хорошо.Тогда как при использовании malloc я могу просто сделать if (!new_mem) { /* handle error */ }.

Поэтому у меня есть вопрос.Можно ли использовать умные указатели вместе с malloc?

Что-то вроде:

SmartPointer<Type> smarty = malloc(sizeof(Type));

Как-то так.

Возможно ли это?

СпасибоБода Чидо.

Ответы [ 9 ]

34 голосов
/ 13 августа 2010

Если вы используете shared_ptr или unique_ptr, вы можете указать пользовательское средство удаления.Например,

struct free_delete
{
    void operator()(void* x) { free(x); }
};

Это можно использовать с shared_ptr следующим образом:

std::shared_ptr<int> sp((int*)malloc(sizeof(int)), free_delete());

Если вы используете unique_ptr, средство удаления является частью unique_ptrтип, поэтому в качестве аргумента шаблона необходимо указать средство удаления:

std::unique_ptr<int, free_delete> up((int*)malloc(sizeof(int)));

Однако при написании C ++ лучше использовать исключения, а не избегать их, особенно в отношении ошибок выделения.,В большинстве случаев вы не можете успешно восстановиться после сбоя выделения в функции, пытающейся выполнить выделение, поэтому исключения могут помочь вам обработать ошибку, если вы действительно способны ее обработать.

9 голосов
/ 13 августа 2010

Вы можете использовать ключевое слово nothrow с оператором new, который будет возвращать NULL, а не исключение.Подробности см. По ссылке ниже: http://www.cplusplus.com/reference/std/new/nothrow/

3 голосов
/ 13 августа 2010

Лучшее решение - использовать new (std::nothrow) Type.Это будет действовать так же, как new Type, но будет давать ноль, а не бросать, если это не удастся.Это будет намного проще, чем пытаться заставить malloc вести себя как new.

Если вам действительно нужно использовать malloc, то не забудьте правильно построить и уничтожить объект:

void* memory = malloc(sizeof(Type));
Type* object = new (memory) Type;
object->~Type();
free(object); // or free(memory)

Вы можете использовать это с некоторыми умными указателями, назначив ему собственное удаление:

void malloc_deleter(Type* object)
{
    object->~Type();
    free(object);
}

if (void* memory = malloc(sizeof(Type)))
{
    Type* object = new (memory) Type;
    std::shared_ptr<Type> ptr(object, malloc_deleter);
    DoStuff(ptr);
}

Но это было бы намного проще, если бы не бросать новый:

if (Type* object = new (std::nothrow) Type)
{        
    std::shared_ptr<Type> ptr(object);
    DoStuff(ptr);
}
1 голос
/ 13 августа 2010

У меня есть вопрос.

Что произойдет, если «Тип» - это тип, конструктор которого может генерировать?В этом случае все еще нужно обрабатывать исключения в блоке try / catch.

Так что это хорошая идея отказаться от подхода, основанного на исключениях?

Я бы сказал, что можно использовать абстрактныйФабричный / фабричный метод проектирования и имеют все «новое» в относительно меньшем наборе файлов / пространств имен / классов, а не разбросанных по всему месту.Это также может помочь ограничить использование блока try / catch сравнительно небольшим кодом.

1 голос
/ 13 августа 2010

Использование nothrow .

Постоянная Nothrow

Это постоянное значение используется как аргумент для оператора нового и оператора новый [], чтобы указать, что эти функции не должен бросать исключения на ошибка, но возвращает нулевой указатель вместо этого.

char* p = new (nothrow) char [1048576];
if (p==NULL) cout << "Failed!\n";
else {
    cout << "Success!\n";
    delete[] p;
}
1 голос
/ 13 августа 2010

Возможно, вы захотите попробовать "размещение нового".См. Какие варианты использования для "размещения новых"?

1 голос
/ 13 августа 2010

Какой код входит в /* handle error */?Есть ли что-то, что вы действительно можете сделать с ошибкой нехватки памяти?Я просто позволил приложению завершаться с помощью стека вызовов (дамп ядра), поэтому у меня есть идея, по крайней мере, об одном возможном месте, которое может вызывать проблемы.хорошая идея, потому что это не гарантирует, что конструкторы вызываются, возможно, оставляя вас с неинициализированными классами, которые могут даже потерпеть крах, если у них есть виртуальные методы.Не беспокойтесь о перехвате исключения, ведь нехватка памяти является исключительным случаем и не должна происходить при обычных запусках приложения.

1 голос
/ 13 августа 2010

Возможно использовать malloc с умными указателями (хотя вы должны привести возвращаемое значение к целевому типу указателя и предоставить собственный освобождающий указатель)Но лучшим вариантом является использование nothrow версии оператора new.

http://www.cplusplus.com/reference/std/new/nothrow/

1 голос
/ 13 августа 2010

Это зависит от того, что SmartPointer делает при уничтожении.Если вы можете указать free в качестве разборки, это может сработать.Например, boost :: shared_ptr позволяет вам указать удалитель.

Я не обратил достаточного внимания на вашу причину этого желания.Я согласен с другими ответами, что использование nothrow new является гораздо лучшей идеей.

...