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

问题描述 投票:0回答:10

我的一些代码仍然使用

malloc
而不是
new
。原因是因为我害怕使用
new
,因为它会抛出异常,而不是返回
NULL
,我可以轻松检查。将每个对
new
的调用包装在
try{}catch(){}
中看起来也不太好。而使用
malloc
时,我可以做
if (!new_mem) { /* handle error */ }

所以我有一个问题。我可以将智能指针与

malloc
一起使用吗?

类似:

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

类似这样的事情。

这可能吗?

c++ malloc new-operator smart-pointers
10个回答
52
投票

如果您使用

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


13
投票

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


4
投票

最好的解决方案是使用

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);
}

2
投票

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

使用

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

只需使用

new
delete
并且不用担心捕获异常,毕竟内存不足是一种例外情况,在应用程序的正常运行中不应发生。


1
投票

这取决于智能指针在销毁时所做的事情。 如果您可以指定

free
作为解除分配器,那就可以了。 例如,boost::shared_ptr 允许您指定删除器。

我没有足够重视你想要这个的原因。 我同意其他答案,即使用 nothrow

new
是一个更好的主意。


1
投票

您可能想尝试“新展示位置”。请参阅“新展示位置”有什么用途?


1
投票

使用不投掷

无投掷常数

该常数值用作 运算符 new 和运算符的参数 new[] 来表明这些函数 不得抛出异常 失败,但返回空指针 相反。

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

1
投票

我有一个问题。

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

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

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


1
投票

对于单行:

unique_ptr<char, void (*)(void*)> buffer( (char*)malloc(size), free );


0
投票

可以将 malloc 与智能指针一起使用(不过,您必须将返回值转换为目标指针类型,并提供自定义释放器)。但更好的选择是使用

nothrow
版本的
new
运算符。

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

© www.soinside.com 2019 - 2024. All rights reserved.