我看到在c++中有多种方法来分配和释放数据,我明白,当你调用malloc时你应该叫自由,当你使用新的操作符应与删除和对它是错误的把两个调用free()(例如,创建新的操作符),但是我不清楚我应该使用malloc / free,当我在现实世界中应该使用新的/删除程序。
如果你是c++专家,请告诉我你在这方面遵循的任何经验法则或惯例。
我看到在c++中有多种方法来分配和释放数据,我明白,当你调用malloc时你应该叫自由,当你使用新的操作符应与删除和对它是错误的把两个调用free()(例如,创建新的操作符),但是我不清楚我应该使用malloc / free,当我在现实世界中应该使用新的/删除程序。
如果你是c++专家,请告诉我你在这方面遵循的任何经验法则或惯例。
当前回答
如果你有C代码,你想移植到c++,你可能会留下任何malloc()调用。对于任何新的c++代码,我建议使用new。
其他回答
malloc和new有一个很大的区别。Malloc分配内存。这对于C语言来说很好,因为在C语言中,一块内存就是一个对象。
在c++中,如果你不处理POD类型(类似于C类型),你必须在内存位置上调用构造函数来实际拥有一个对象。非pod类型在c++中非常常见,因为许多c++特性使对象自动变为非pod类型。
New分配内存并在该内存位置上创建一个对象。对于非pod类型,这意味着调用构造函数。
如果你这样做:
non_pod_type* p = (non_pod_type*) malloc(sizeof *p);
您获得的指针不能被解引用,因为它不指向对象。在使用它之前,您需要调用它的构造函数(这是使用placement new完成的)。
另一方面,如果你有:
non_pod_type* p = new non_pod_type();
你得到一个总是有效的指针,因为new创建了一个对象。
即使是POD类型,两者之间也有显著差异:
pod_type* p = (pod_type*) malloc(sizeof *p);
std::cout << p->foo;
这段代码将打印一个未指定的值,因为由malloc创建的POD对象没有初始化。
使用new,可以指定要调用的构造函数,从而获得定义良好的值。
pod_type* p = new pod_type();
std::cout << p->foo; // prints 0
如果你真的想要它,你可以使用use new来获得未初始化的POD对象。有关更多信息,请参阅另一个答案。
另一个区别是失败时的行为。当它分配内存失败时,malloc返回一个空指针,而new则抛出异常。
前者要求您在使用它之前测试返回的每个指针,而后者将始终产生有效的指针。
基于这些原因,在c++代码中应该使用new,而不是malloc。但即便如此,你也不应该“公开”使用新的内容,因为它会占用你以后需要发布的资源。当你使用new时,你应该立即将它的结果传递给一个资源管理类:
std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak
除非被迫使用C,否则永远不要使用malloc。总是使用new。
如果你需要大量的数据,可以这样做:
char *pBuffer = new char[1024];
尽管这是不正确的,但要小心:
//This is incorrect - may delete only one element, may corrupt the heap, or worse...
delete pBuffer;
相反,你应该在删除数据数组时这样做:
//This deletes all items in the array
delete[] pBuffer;
new关键字是c++实现它的方式,它将确保你的类型的构造函数被调用。new关键字也更加类型安全,而malloc根本不是类型安全的。
我认为使用malloc有益的唯一方式是需要改变数据缓冲区的大小。new关键字没有类似realloc的方式。realloc函数可能能够更有效地扩展内存块的大小。
值得一提的是,你不能将new/free和malloc/delete混合使用。
注:本题部分答案无效。
int* p_scalar = new int(5); // Does not create 5 elements, but initializes to 5
int* p_array = new int[5]; // Creates 5 elements
只有当对象的生命周期与创建它的作用域不同时才需要动态分配(这也适用于使作用域变小或变大),并且您有特定的原因按值存储它不起作用。
例如:
std::vector<int> *createVector(); // Bad
std::vector<int> createVector(); // Good
auto v = new std::vector<int>(); // Bad
auto result = calculate(/*optional output = */ v);
auto v = std::vector<int>(); // Good
auto result = calculate(/*optional output = */ &v);
从c++ 11开始,我们有std::unique_ptr来处理已分配的内存,它包含已分配内存的所有权。Std::shared_ptr是为必须共享所有权而创建的。(你需要的比你在一个好的程序中期望的要少)
创建一个实例变得非常简单:
auto instance = std::make_unique<Class>(/*args*/); // C++14
auto instance = std::unique_ptr<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::unique_ptr<Class[]>(new Class[](42)); // C++11
c++ 17还增加了std::optional,这可以防止你需要内存分配
auto optInstance = std::optional<Class>{};
if (condition)
optInstance = Class{};
一旦'instance'超出作用域,内存就会被清理。转让所有权也很容易:
auto vector = std::vector<std::unique_ptr<Interface>>{};
auto instance = std::make_unique<Class>();
vector.push_back(std::move(instance)); // std::move -> transfer (most of the time)
那你什么时候还需要新的?从c++ 11开始几乎没有。大多数情况下你使用std::make_unique,直到你遇到一个通过原始指针转移所有权的API。
auto instance = std::make_unique<Class>();
legacyFunction(instance.release()); // Ownership being transferred
auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr
在c++ 98/03中,您必须进行手动内存管理。如果您是这种情况,请尝试升级到标准的最新版本。如果你被卡住了:
auto instance = new Class(); // Allocate memory
delete instance; // Deallocate
auto instances = new Class[42](); // Allocate memory
delete[] instances; // Deallocate
确保正确跟踪所有权,以免出现内存泄漏!Move语义也不能工作。
那么,在c++中什么时候需要malloc呢?唯一有效的原因是分配内存并在以后通过放置new初始化它。
auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory
auto instance = new(instanceBlob)Class{}; // Initialize via constructor
instance.~Class(); // Destroy via destructor
std::free(instanceBlob); // Deallocate the memory
尽管如此,上面的操作是有效的,这也可以通过new操作符来完成。vector就是一个很好的例子。
最后,我们仍然有一个房间里的大象:C。如果你必须使用一个在c++代码中分配内存并在C代码中释放内存的C库(或者相反),你就被迫使用malloc/free。
如果你是在这种情况下,忘记虚函数、成员函数、类……只有包含pod的结构才被允许。
规则的一些例外情况:
您正在编写一个具有高级数据结构的标准库,其中malloc是合适的 你必须分配大量的内存(在10GB文件的内存副本中?) 您拥有阻止您使用某些构造的工具 您需要存储不完整的类型
从较低的角度来看,new将在提供内存之前初始化所有内存,而malloc将保留内存的原始内容。
在c++中总是使用new。如果你需要一个无类型的内存块,你可以直接使用operator new:
void *p = operator new(size);
...
operator delete(p);