C++的一些特性(4)

C++的内存管理

内存泄露

在普通的 C 语言程序中。我们可以使用 malloc 函数动态地分配内存,然而若我们没有及时地对使用完成的内存进行释放,就会造成内存泄露。

来看下面的一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>

void f(void)
{
void* s;
s = malloc(50);
return;
}
int main(void)
{
while (true) f(); /* Malloc函数迟早会由于内存泄漏而返回NULL*/
return 0;
}

我们平时在用 PC 的时候可能没有任何感觉,毕竟如果占用内存过多我们关掉这个程序,甚至说重启一下电脑,肯定就没有这个问题了。但是内存泄露往往不发生在 PC 当中,而是会在服务器上,而服务器中运行的服务一般是常驻程序,一般情况下进程不允许被关闭更不允许随便重启,因此若服务的进程存在上述的内存泄露则迟早会耗尽服务器的内存资源。

智能指针

C++ 提出了智能指针这样的概念,类似现在高级语言的垃圾回收机制。

C++支持以下四种类型的智能指针

  • std::auto_ptr
  • std::shared_ptr
  • std::weak_ptr
  • std::unique_ptr

std::shared_ptr

共享式指针,可以有多个指针指向同一块内存,内部对内存会有一个引用计数,当一块内存的引用计数归0之后自动释放空间,修改指针指向会导致引用次数改变,在调试窗口可以看到某个指针指向内存的强引用次数。

引用计数可以使用成员函数 use_count() 获得。shared_ptr 内部实现了多种运算符的重载,比如我们常见的指针取值 *

除了上面的初始化方式外,我们还可以使用函数 make_shared<T> 去构造,例如 auto obj4 = make_shared<int>(1000);

释放除了直接释放外,还可以使用成员函数 reset() 去释放当前的对象,若指针所占区域非独占则引用计数 -1 否则直接释放内存区域,若参数使用了一个新的指针,则会导致当前对象指向这个指针。

成员函数 get() 可以获取原始指针,但是获取出来的指针就不归智能指针管了,也不会计数,一旦没有 shared_ptr 指向那一块内存区域后就会马上释放。

成员函数 swap() 可以交换两个智能指针。

std::weak_ptr

weak_ptr是弱智能指针对象,它不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的智能指针。将一个weak_ptr绑定到一个shared_ptr对象,不会改变shared_ptr的引用计数。一旦最后一个所指向对象的shared_ptr被销毁,所指向的对象就会被释放,即使此时有weak_ptr指向该对象,所指向的对象依然被释放。

用成员函数 expired() 可以判断对象是否被释放。

用成员函数 lock() 可以获取对象的指针。

std::unique_ptr

独占式智能指针,引用计数只能为1,为0则释放,尝试赋值会报错。