Действительно ли возможно использовать C++ интеллектуальные указатели вместе с C malloc?

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

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

Что-то как:

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

Что-то вроде этого.

Действительно ли это возможно?

Спасибо, Boda Cydo.

23
задан Gilles 'SO- stop being evil' 13 August 2010 в 13:59
поделиться

9 ответов

Если вы используете 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 ++, особенно в отношении сбоев выделения. В большинстве случаев вы не можете успешно восстановиться после сбоя выделения в функции, пытающейся выполнить выделение, поэтому исключения могут помочь вам обработать ошибку там, где вы действительно можете ее обработать.

39
ответ дан 29 November 2019 в 01:18
поделиться

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

1
ответ дан 29 November 2019 в 01:18
поделиться

Используйте nothrow .

Константа Нотроу

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

char* p = new (nothrow) char [1048576];
if (p==NULL) cout << "Failed!\n";
else {
    cout << "Success!\n";
    delete[] p;
}
1
ответ дан 29 November 2019 в 01:18
поделиться

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

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

1
ответ дан 29 November 2019 в 01:18
поделиться

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

9
ответ дан 29 November 2019 в 01:18
поделиться

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

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

1
ответ дан 29 November 2019 в 01:18
поделиться

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

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

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

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

1
ответ дан 29 November 2019 в 01:18
поделиться

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

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

Просто используйте new и delete и не беспокойтесь об обнаружении исключения, ведь нехватка памяти ЯВЛЯЕТСЯ исключительным случаем и не должна происходить при нормальном запуске приложения. .

1
ответ дан 29 November 2019 в 01:18
поделиться

Лучшим решением будет использование 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);
}
3
ответ дан 29 November 2019 в 01:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: