C++智能指针实例详解

2020-01-06 12:36:29于海丽


我们从代码开始分析:


void TestAutoPtr() {
std::auto_ptr<Simple> my_memory(new Simple(1));  // 创建对象,输出:Simple:1
if (my_memory.get()) {              // 判断智能指针是否为空
my_memory->PrintSomething();          // 使用 operator-> 调用智能指针对象中的函数
my_memory.get()->info_extend = "Addition";   // 使用 get() 返回裸指针,然后给内部对象赋值
my_memory->PrintSomething();          // 再次打印,表明上述赋值成功
(*my_memory).info_extend += " other";      // 使用 operator* 返回智能指针内部对象,然后用“.”调用智能指针对象中的函数
my_memory->PrintSomething();          // 再次打印,表明上述赋值成功
 }
}                       //my_memory栈对象即将结束生命期,析构堆对象Simple(1)

执行结果为:


Simple: 1
PrintSomething:
PrintSomething: Addition
PrintSomething: Addition other
~Simple: 1

上述为正常使用 std::auto_ptr 的代码,一切似乎都良好,无论如何不用我们显示使用该死的 delete 了。
 
其实好景不长,我们看看如下的另一个例子:


void TestAutoPtr2() {
 std::auto_ptr<Simple> my_memory(new Simple(1));
 if (my_memory.get()) {
  std::auto_ptr<Simple> my_memory2;  // 创建一个新的 my_memory2 对象
  my_memory2 = my_memory;       // 复制旧的 my_memory 给 my_memory2
  my_memory2->PrintSomething();    // 输出信息,复制成功
  my_memory->PrintSomething();    // 崩溃
 }
}

最终如上代码导致崩溃,如上代码时绝对符合 C++ 编程思想的,居然崩溃了,跟进 std::auto_ptr 的源码后,我们看到,罪魁祸首是“my_memory2 = my_memory”,这行代码,my_memory2 完全夺取了 my_memory 的内存管理所有权,导致 my_memory 悬空,最后使用时导致崩溃。

所以,使用 std::auto_ptr 时,绝对不能使用“operator=”操作符。作为一个库,不允许用户使用,确没有明确拒绝,多少会觉得有点出乎预料。
 
看完 std::auto_ptr 好景不长的第一个例子后,让我们再来看一个:


void TestAutoPtr3() {
 std::auto_ptr<Simple> my_memory(new Simple(1));
 
 if (my_memory.get()) {
  my_memory.release();
 }
}

执行结果为:


Simple: 1

看到什么异常了吗?我们创建出来的对象没有被析构,没有输出“~Simple: 1”,导致内存泄露。当我们不想让 my_memory 继续生存下去,我们调用 release() 函数释放内存,结果却导致内存泄露(在内存受限系统中,如果my_memory占用太多内存,我们会考虑在使用完成后,立刻归还,而不是等到 my_memory 结束生命期后才归还)。