我的一些代码仍然使用
malloc
而不是 new
。原因是因为我害怕使用 new
,因为它会抛出异常,而不是返回 NULL
,我可以轻松检查。将每个对 new
的调用包装在 try{}catch(){}
中看起来也不太好。而使用 malloc
时,我可以做 if (!new_mem) { /* handle error */ }
。
所以我有一个问题。我可以将智能指针与
malloc
一起使用吗?
类似:
SmartPointer<Type> smarty = malloc(sizeof(Type));
类似这样的事情。
这可能吗?
如果您使用
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++ 时,最好正确使用异常,而不是避免异常,尤其是在分配失败方面。 在大多数情况下,您无法成功地从尝试进行分配的函数中的分配失败中恢复,因此异常可以帮助您在实际有能力处理错误的情况下处理错误。
您可以在 new 运算符中使用 nothrow 关键字,这将返回 NULL 而不是抛出异常。详情请见以下链接: http://www.cplusplus.com/reference/std/new/nothrow/
最好的解决方案是使用
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);
}
/* handle error */
里面有什么代码?对于内存不足错误,您实际上可以做些什么吗?我只是让应用程序通过调用堆栈(核心转储)终止,因此我至少知道一个可能导致问题的地方。
使用
malloc
为 C++ 类和对象分配内存不是一个好主意,因为它不能确保调用构造函数,可能会留下未初始化的类,如果它们具有虚方法,甚至可能会崩溃。
只需使用
new
和 delete
并且不用担心捕获异常,毕竟内存不足是一种例外情况,在应用程序的正常运行中不应发生。
这取决于智能指针在销毁时所做的事情。 如果您可以指定
free
作为解除分配器,那就可以了。 例如,boost::shared_ptr 允许您指定删除器。
我没有足够重视你想要这个的原因。 我同意其他答案,即使用 nothrow
new
是一个更好的主意。
您可能想尝试“新展示位置”。请参阅“新展示位置”有什么用途?
使用不投掷。
无投掷常数
该常数值用作 运算符 new 和运算符的参数 new[] 来表明这些函数 不得抛出异常 失败,但返回空指针 相反。
char* p = new (nothrow) char [1048576];
if (p==NULL) cout << "Failed!\n";
else {
cout << "Success!\n";
delete[] p;
}
我有一个问题。
如果“Type”是构造函数可以抛出异常的类型,会发生什么?在这种情况下,仍然需要在 try/catch 块中处理异常。
那么放弃基于异常的方法是个好主意吗?
我想说,人们可以使用抽象工厂/工厂方法设计模式,并将所有“新内容”放在相对较少的一组文件/命名空间/类中,而不是将它们分散在各处。这也可能有助于将 try/catch 块的使用限制在相对较少的代码中。
对于单行:
unique_ptr<char, void (*)(void*)> buffer( (char*)malloc(size), free );
可以将 malloc 与智能指针一起使用(不过,您必须将返回值转换为目标指针类型,并提供自定义释放器)。但更好的选择是使用
nothrow
版本的 new
运算符。