C++智能指针: auto_ptr, shared_ptr, unique_ptr, weak_ptr

本文参考C++智能指针简单剖析

内存泄露

我们知道一个对象(变量)的生命周期结束的时候, 会自动释放掉其占用的内存(例如局部变量在包含它的第一个括号结束的时候自动释放掉内存)

int main () {
    {
        int a = 1;
        printf("%d\n", a);
    }
    {
        a = 2;
        printf("%d\n", a);
    }
}

这样会编译错误.

但是如果这样写呢?

void func(int &o) {
    int *p = new int(o);
    return;
}

程序结束的时候会自动释放p的内存, 但是由new算符创建的匿名变量却一直留在内存中, 这就为内存泄露留下了隐患.
所以在程序结尾要加上delete p, 释放掉p指向的变量占用的内存.

那么能不能在指针过期的时候自动释放掉它指向的内存呢?
可惜它不是具有析构函数的类对象指针.
如果这个指针本身就是个对象, 它就可以实现在指针本身离开作用域的时候释放其指向的内存的析构函数了.

这就是auto_ptr, shared_ptr, unique_ptr几个智能指针背后的设计思想.可以理解为这个指针本身就是一个对象, 因为它具有对象的行为.

可以将上述有问题的代码改写为这样:

void func(int &o) {
    auto_ptr<int> p(new int(o));
}

这样在函数结束的时候内存就会被释放了.

智能指针

这个东西是在C++98提供的.C++11已经抛弃了它并且提供了另外两种解决方案.
如果没有C++11的话就只能使用这个东西了.

不允许隐形转换

所有的智能指针都有一个explicit构造函数, 以指针为参数.

这个东西大概可以这样写

template <class T>
class auto_ptrs {
private:
    T* ptr;
public:
    explicit auto_ptrs (T* p = 0): ptr(p) {}
    ~auto_ptrs() { delete ptr; printf("delete\n"); }
};
int main () {
    {
        auto_ptrs<int> p (new int(1));
        auto_ptr<int> ptr, pt(new int(2));
        ptr = auto_ptr<int>(new int(3));
    }
}

只能用于堆内存

int main() {
    int a = 0;
    std:: auto_ptr<int> p(&a);
}

这样写是错误的, 因为它会在main&a执行delete操作, 而a位于栈内存, 不能被delete.

unique_ptr代替auto_ptr

如果将一个指针赋值给另一个指针呢?

class Int{
    int a;
public:
    int J() {return a;}
    Int(int _) : a(_) {}
    ~Int() { printf("delete\n"); }
};
int main() {
    auto_ptr<Int> p (new Int(123456789));
    auto_ptr<Int> q;
    q = p;
}

如果在p, q作用域结束的时候分别delete一次, 那么就会delete同一个变量两次, 这样是不行的.

有很多种解决方案可以解决这个问题:

  • 深度复制, 就是将指针指向的内存复制一遍再让另一个指针指向它.
  • 转让所有权, 由于一个对象只能由一个对象所拥有, 另一个就变空指针了, 只让拥有对象的指针删除该对象.(auto_ptrunique_ptr的策略)
  • 跟踪引用特定对象的智能指针数.——引用计数(shared_ptr的策略), 如果一个对象被引用了p次, 那么得当指针全部销毁时对象才会销毁.

但是用auto_ptr还是有一个问题, 如果q = p之后又调用了*p, 对一个空指针解除引用程序是会崩溃的.
unique_ptr的好处是如果你这样写

unique_ptr<Int> p (new Int(1));
unique_ptr<Int> q;
q = p;

你会得到一个编译错误, 原因是避免潜在的内存崩溃问题.
但是如果你把一个临时的unique_ptr赋值给unique_ptr却不会出现问题, 这是它聪明的地方.
例如

unique_ptr<int> func(int &a) {
    unique_ptr<int> p(&a);
    return p;
}

或者

unique_ptr<int> a;
a = unique_ptr<int> (new int(199));

你甚至可以将unique_ptr显性转化为shared_ptr, 当然对象也被接管.

原文地址:https://www.cnblogs.com/qdscwyy/p/9830139.html

时间: 2024-11-05 20:42:11

C++智能指针: auto_ptr, shared_ptr, unique_ptr, weak_ptr的相关文章

boost智能指针之shared_ptr和weak_ptr

std::auto_ptr很多的时候并不能满足我们的要求,比如auto_ptr不能用作STL容器的元素.boost的smart_ptr中提供了4种智能指针和2种智能指针数组来作为std::auto_ptr的补充. shared_ptr<boost/shared_ptr.hpp>:使用shared_ptr进行对象的生存期自动管理,使得分享资源所有权变得有效且安全. weak_ptr<boost/weak_ptr.hpp>:weak_ptr 是 shared_ptr 的观察员.它不会干

详解Boost库智能指针(shared_ptr &amp;&amp; scoped_ptr &amp;&amp; weak_ptr )

我们先来解释一下什么叫智能指针? 智能指针是利用RAII(在对象的构造函数中执行资源的获取(指针的初始化),在析构函数中释放(delete 指针):这种技法把它称之为RAII(Resource Acquisition Is Initialization:资源获取即初始化))来管理资源. 其本质思想是:将堆对象的生存期用栈对象(智能指针)来管理.也就是当new一个堆对象的时候,立刻用智能指针来接管,具体做法是在构造函数中进行初始化(用一个指针指向堆对象),在析构函数调用delete来释放堆对象.由

【STL学习】智能指针之shared_ptr

前面已经学习过auto_ptr,这里补充另外一种智能指针,比auto_ptr要更强力更通用的shared_ptr. shared_ptr 简介及使用选择  几乎所有的程序都需要某种形式的引用计数智能指针,这种指针让我们不再需要为两个对象或更多对象共享的对象的生命周期而编写复杂的逻辑(写起来有点绕口),当被共享的对象引用计数降为0时,被共享对象被自动析构. 引用计数指针分为插入式(instrusive)和非插入式(non-instrusive)两种.前者要求它所管理的类提供明确的函数或数据成员用于

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析,左值与右值

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析 by 小威威 1. 知识引入 在C++编程中,动态分配的内存在使用完毕之后一般都要delete(释放),否则就会造成内存泄漏,导致不必要的后果.虽然大多数初学者都会有这样的意识,但是有些却不以为意.我曾问我的同学关于动态内存的分配与释放,他的回答是:"只要保证new和delete成对出现就行了.如果在构造函数中new(动态分配内存),那么在析构函数中delete(释放)就可以避免内存泄漏了!" 事实果真如此么?

【C++智能指针 auto_ptr】

<More Effective C++>ITEM M9中提到了auto_ptr,说是当异常产生的时候,怎么释放为对象分配的堆内存,避免重复编写内存释放语句. PS:这里书里面提到函数退出问题,函数退出会清理栈内存,不管是怎么正常退出还是异常退出(仅有一种例外就是当你调用 longjmp 时.Longjmp 的这个缺点是 C++率先支持异常处理的主要原因).建立在此基础上我们才把对指针的删除操作封装到一个栈对象里面.这样函数退出(异常或是正常)就会调用对象的析构函数,达到我们自动清理所封装指针指

智能指针auto_ptr详解

概述:C++中有很多种智能指针,auto_ptr就是其中的一种,该智能指针主要是为了解决"因程序异常退出发生的内存泄漏"这类问题的. 我们先来看下面的问题代码 #include<iostream> #include<memory> #include<exception> using namespace std; //一般指针的处理方式 template<typename T> class OldClass { public: OldCla

C++中的智能指针(auto_ptr)

实际上auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,使用它不必每次都手动调用delete去释放内存.当然有利也有弊,也不是完全完美的. 本文从下面的8个方面来总结auto_ptr使用的大部分内容. 1. auto_ptr是什么? auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个这样拥有者(auto_ptr).当auto_ptr对象生命

C++智能指针 auto_ptr

C++智能指针 auto_ptr auto_ptr 是一个轻量级的智能指针, 定义于 memory (非memory.h)中, 命名空间为 std. auto_ptr 适合用来管理生命周期比较短或者不会被远距离传递的动态对象, 最好是局限于某个函数内部或者是某个类的内部. 使用方法: std::auto_ptr<int> pt(new int(10)); pt.reset(new int(11)); 成员函数 3个重要的函数: (1) get 获得内部对象的指针, 由于已经重载了()方法, 因

C++智能指针--auto_ptr指针

auto_ptr是C++标准库提供的类模板,头文件<memory>,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者.当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有的动态内存自动释放.即使发生异常,通过异常的栈展开过程也能将动态内存释放.auto_ptr不支持new数组. auto_ptr的出现,主要是为了解决"有异常抛出时发生内存泄漏"的问题.如下的简单代码是这类问题的一个简单示