前言
下面这段代码看起来正常,但事实在特殊情况下f函数可能无法释放这个a资源。
void f() { A * a = new A(); ... delete a; }
例如:
1.如果在中间这段代码中有一个过早的return语句,且刚好被执行那么就会出现内存泄漏,这时你可能会说在每个return前都加一个delete a;语句。不得不说这种做法可以避免上述出现的问题,但会导致代码中随处可见的delete a;语句显得很乱且臃肿。
2.如果在中间这段代码中出现一个异常,也会导致内存泄漏。
单纯靠着delete a;语句去释放内存是行不通的。
智能指针
这时就要用到智能指针这个东西了。自动释放内存
- 智能指针会帮程序员来管理对象。
- 在智能智能释放时自动会调用所管理对象的析构函数。
头文件:memory
使用方法
虽然智能指针种类较多但是用法都一样,下面以unique_ptr为例。在申请到内存时将会交给unique_ptr接管,在执行完f函数后a对象将会自动调用析构函数。
void f() { ... std::unique_ptr<A> a(new A()); ... }
unique_ptr
对象的所有权可以从一个独占指针转移到另一个指针,
转移方式:对象始终只能有一个指针作为其所有者。
当独占指针离开其作用域或将要拥有不同的对象时,它会自动释放自己所管理的对象。
实现unique_ptr类
template<class T> class Unique_ptr { public: Unique_ptr(T* ptr) { this->ptr = ptr; } ~Unique_ptr() { if (ptr != nullptr) { delete ptr; cout << "释放ptr对象" << endl; ptr = nullptr; } } T& operator*() { return *ptr; } T* get() { return ptr; } T* operator->() { return ptr; } private: Unique_ptr(const Unique_ptr& other) = delete; Unique_ptr& operator=(const Unique_ptr& other) = delete; private: T* ptr; };
使用uniquePtr
int main() { unique_ptr<string> p1(new string("hellow")); cout << *p1 << endl; *p1 = "你好!"; cout << *p1 << endl; return 0; }
shared_ptr
共享指针将记录有多少个指针共同享有某个对象的所有权。当有更多指针被设置为指向该对象时,引用计数随之增加;当指针和对象分离时,则引用计数也相应减少。当引用计数降低至0时,该对象被删除。
实现SharedPtr
template<class T> class SharedPtr { public: SharedPtr(T* ptr = nullptr) { count = new int(1); this->ptr = ptr; } SharedPtr(SharedPtr& other) { *other.count += 1; count = other.count; ptr = other.ptr; } SharedPtr& operator=(SharedPtr& other) { *other.count += 1; count = other.count; ptr = other.ptr; return *this; } ~SharedPtr() { --(*count); cout << *count << "\t" << ptr << endl; if (ptr != nullptr && 0 == *count) { cout << "释放!" << endl; delete ptr; ptr = nullptr; delete count; count = nullptr; } } T& operator*() const { return *ptr; } T* get() const { return ptr; } T* operator->() const { return ptr; } int use_count(void) const { return *count; } private: T* ptr; int* count; };
使用shared_ptr
int main() { Shared_ptr<int> p1(new int); Shared_ptr<int> p2(p1); *p1 = 10; cout << *p1 << endl; cout << *p2 << endl; cout << p1.use_count() << endl;//获取当前引用个数 return 0; }
weak_ptr
C++11标准虽然将 weak_ptr 定位为智能指针的一种,但该类型指针通常不单独使用(没有实际用处),只能和shared_ptr类型指针搭配使用。甚至可以将 weak_ptr 类型指针视为 shared_ptr 指针的一种辅助工具,借助weak_ptr类型指针, 我们可以获取 shared_ptr 指针的一些状态信息,比如有多少指向相同的 shared_ptr 指针、shared_ptr 指针指向的堆内存是否已经被释放等等。
使用weak_ptr
class Test { public: Test() { cout << "Test()" << endl; } ~Test() { cout << "~Test()" << endl; } void Output() const { cout << "Output()" << endl; } }; weak_ptr<Test> test() { shared_ptr<Test> p(new Test); return p; } int main() { weak_ptr<Test> w1 = test(); shared_ptr<Test> s1 = w1.lock();//检查对象是否被释放 cout << s1 << endl; if (s1) { cout << "对象依旧存在!" << endl; } else { cout << "对象已被释放" << endl; } return 0; }
在Effective C++第13条款中也建议:如果想要手工释放资源,容易发送某些错误。使用这类智能指针往往能让程序员更少犯错。