malloc与free是C++/C语言用于动态内存分配的标准库函数,因此在 C++ 中也可以使用,但是因为缺乏类型安全性(需要手动转换指针类型)和自动内存管理的功能,通常不推荐在C++中使用。对于非内部数据类型的对象而言,使用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数,不在编译器控制权限之内,不应当去执行构造函数和析构函数的任务。因此往往还需要定义初始化和销毁清除功能的函数来执行构造和析构,而使用new与delete则覆盖了这些功能。
new/delete是C++的运算符,用于申请动态内存和释放内存,同时增加了类型安全性,并且可以调用构造函数和析构函数,完成初始化与清理释放的工作,能够兼容C++的异常安全机制,但未正确处理异常时,会导致未定义行为。malloc/free与new/delete都应当成对出现,存在分配内存,就应当及时销毁。当然,如果用free释放”new创建的动态对象”,或用delete释放”malloc申请的动态内存”,那么该对象因无法执行析构函数而可能导致程序出错。
智能指针是现代 C++ 中用来自动管理指针所指向的对象生命周期的对象。它们通过在构造时获取对动态分配对象的所有权,并在析构时释放这个所有权来管理内存。可以有效地避免内存管理和生命周期管理中的常见错误。
其中:
shared_ptr支持共享所有权,允许多个shared_ptr对象共享同一个资源。当最后一个指向该资源的shared_ptr对象销毁时,资源才会被释放。weak_ptr是shared_ptr的弱引用,指的是可以使用该对象,但是没有所有权,由真正拥有其所有权的来负责释放。不增加引用计数,通常用于解决shared_ptr循环引用的问题。
unique_ptr表示独占所有权的智能指针,意味着同一时间内只能有一个unique_ptr 对象拥有一个给定资源的所有权。当unique_ptr对象销毁或绑定到一个新的资源时,其原来拥有的资源会被释放。unique_ptr性能优于shared_ptr且内存占用上小于shared_ptr,因为shared_ptr在拷贝或者释放时候,都需要操作引用计数,需要维护它指向的对象的线程安全引用计数和一个控制块,这使得它比unique_ptr更重量级。
因此如果程序要使用多个指向同一个对象的指针,应选择shared_ptr。如果函数使用new分配内存,并返还指向该内存的指针,将其返回类型声明为unique_ptr是不错的选择。这样,所有权转让给接受返回值的unique_ptr,而该智能指针将负责调用delete。
常用的初始化shared_ptr两种代码如下:
std::shared_ptr<Type> p1 = new Type;
std::shared_ptr<Type> p2 = std::make_shared<Type>();
new方式的初始化方式共有两次内存分配操作:new Type分配对象和为p1分配控制块(control block),控制块用于存放引用计数等信息。而make_shared初始化方式只有一次内存申请(是由make_shared的函数实现决定的),所以建议使用make_shared方式进行初始化。