Часть моего кода все еще использует malloc
вместо new
. Причина состоит в том, потому что я боюсь использовать new
потому что это выдает исключение вместо возврата NULL
, на который я могу легко проверить. Обертывание каждого вызова к new
в a try{}catch(){}
также не выглядит что хорошим. Принимая во внимание, что при использовании malloc
Я могу просто сделать if (!new_mem) { /* handle error */ }
.
Поэтому у меня есть вопрос. Я могу использовать интеллектуальные указатели вместе с malloc
?
Что-то как:
SmartPointer<Type> smarty = malloc(sizeof(Type));
Что-то вроде этого.
Действительно ли это возможно?
Спасибо, Boda Cydo.
Если вы используете 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 ++, особенно в отношении сбоев выделения. В большинстве случаев вы не можете успешно восстановиться после сбоя выделения в функции, пытающейся выполнить выделение, поэтому исключения могут помочь вам обработать ошибку там, где вы действительно можете ее обработать.
Вы можете попробовать «новое размещение». См. Какое использование используется для «размещения нового»?
Используйте nothrow .
Константа Нотроу
Это постоянное значение используется как аргумент для оператора new и оператора new [], чтобы указать, что эти функции не должен вызывать исключение сбой, но вернуть нулевой указатель вместо.
char* p = new (nothrow) char [1048576];
if (p==NULL) cout << "Failed!\n";
else {
cout << "Success!\n";
delete[] p;
}
Можно использовать malloc с интеллектуальными указателями (вы должны преобразовать возвращаемое значение в тип целевого указателя и предоставить настраиваемый освободитель). Но лучше использовать nothrow
версию оператора new
.
Вы можете использовать ключевое слово nothrow с оператором new, который вернет NULL, а не выбросить исключение. Подробнее см. Ссылку ниже: http://www.cplusplus.com/reference/std/new/nothrow/
Это зависит от того, что делает SmartPointer при уничтожении. Если вы можете указать free
в качестве деаллокатора, это может сработать. Например, boost::shared_ptr позволяет указать деаллокатор.
Я не уделил достаточно внимания вашей причине, по которой вы хотите этого. Я согласен с другими ответами, что использование nothrow new
- гораздо лучшая идея.
У меня вопрос.
Что произойдет, если "Type" - это тип, конструктор которого может бросать? В этом случае все равно нужно обрабатывать исключения в блоке try/catch.
Так что хорошая ли это идея отказаться от подхода, основанного на исключениях?
Я бы сказал, что можно использовать паттерн проектирования Abstract Factory/Factory Method и располагать все "new" в относительно меньшем наборе файлов/пространств имен/классов, а не разбрасывать их повсюду. Это также может помочь ограничить использование блока try/catch относительно меньшим количеством кода.
Какой код находится в / * ошибка обработки * /
? Есть ли что-нибудь, что можно сделать с ошибкой нехватки памяти? Я просто позволяю приложению завершиться с помощью стека вызовов (дампа ядра), поэтому у меня есть представление хотя бы об одном возможном месте, которое может вызывать проблемы.
Использование malloc
для выделения памяти для классов и объектов C ++ не является хорошей идеей, потому что это не гарантирует, что конструкторы вызываются, что может оставить вас с неинициализированными классами, которые могут даже выйти из строя, если у них есть виртуальные методы.
Просто используйте new
и delete
и не беспокойтесь об обнаружении исключения, ведь нехватка памяти ЯВЛЯЕТСЯ исключительным случаем и не должна происходить при нормальном запуске приложения. .
Лучшим решением будет использование new (std::nothrow) Type
. Он будет действовать так же, как new Type
, но в случае неудачи будет выдавать null, а не бросать. Это будет намного проще, чем пытаться заставить 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);
}
Но это было бы намного проще, используя не бросающий new:
if (Type* object = new (std::nothrow) Type)
{
std::shared_ptr<Type> ptr(object);
DoStuff(ptr);
}