是否可以将C ++智能指针与C的malloc一起使用?

时间:2010-08-13 13:58:48

标签: c++ malloc new-operator smart-pointers

我的部分代码仍使用malloc代替new。原因是因为我害怕使用new因为它抛出异常,而不是返回NULL,我可以轻松检查。将new中的try{}catch(){}的每次通话都包含在内也看起来不那么好。使用malloc时我可以if (!new_mem) { /* handle error */ }

因此我有一个问题。我可以将智能指针与malloc一起使用吗?

类似的东西:

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

像这样。

这可能吗?

谢谢,Boda Cydo。

10 个答案:

答案 0 :(得分:34)

如果您使用的是shared_ptrunique_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 ++时,最好正确使用异常,而不是避免使用异常,尤其是在分配失败方面。在大多数情况下,您无法从尝试进行分配的函数中的分配失败中成功恢复,因此异常可以帮助您处理实际能够处理它的错误。

答案 1 :(得分:9)

您可以对new运算符使用nothrow关键字,它将返回NULL而不是抛出异常。详情见下面的链接: http://www.cplusplus.com/reference/std/new/nothrow/

答案 2 :(得分:3)

最佳解决方案是使用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);
}

但是使用非投掷新内容会更简单:

if (Type* object = new (std::nothrow) Type)
{        
    std::shared_ptr<Type> ptr(object);
    DoStuff(ptr);
}

答案 3 :(得分:1)

这取决于SmartPointer在销毁时的作用。如果您可以将free指定为解除分配器,则可以使用。例如,boost :: shared_ptr允许您指定删除器。

我没有足够重视你想要这个的原因。我同意其他答案,使用nothrow new是一个更好的主意。

答案 4 :(得分:1)

可以将malloc与智能指针一起使用(您必须将返回值强制转换为目标指针类型,并提供自定义解除分配器)。但更好的选择是使用nothrow运算符的new版本。

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

答案 5 :(得分:1)

/* handle error */中的代码是什么?对于内存不足错误,您有什么可以实际做的吗?我只是让应用程序以一个调用堆栈(核心转储)终止,所以我知道至少有一个可能导致问题的地方。

使用malloc为C ++类和对象分配内存不是一个好主意,因为它不会确保调用构造函数,可能会留下未初始化的类,如果它们有虚拟方法,甚至可能会崩溃

只需使用newdelete并且不用担心捕获异常,在所有内存耗尽之后这是一个例外情况,并且不应该在应用程序的正常运行中发生。

答案 6 :(得分:1)

您可能想尝试“放置新”。见What uses are there for "placement new"?

答案 7 :(得分:1)

使用nothrow

  

Nothrow常数

     

此常量值用作   运算符new和运算符的参数   new []表示这些功能   不得抛出异常   失败,但返回一个空指针   代替。

char* p = new (nothrow) char [1048576];
if (p==NULL) cout << "Failed!\n";
else {
    cout << "Success!\n";
    delete[] p;
}

答案 8 :(得分:1)

我有一个问题。

如果“Type”是一个构造函数可以抛出的类型,会发生什么?在这种情况下,仍然需要处理try / catch块中的异常。

那么放弃基于异常的方法是个好主意吗?

我想说的是,人们可以使用抽象工厂/工厂方法设计模式,并且在相对较少的文件/命名空间/类集中拥有所有“新”,而不是将它们分散在各处。这也可能有助于将try / catch块的使用限制为相对较小的代码。

答案 9 :(得分:0)

对于一个班轮: unique_ptr<char, void (*)(void*)> buffer( (char*)malloc(size), free );