所有权与智能指针
没错,技术博主开始写技术文了
从我开始学C/C++的时候,指针和内存管理就是最让我头疼的东西:要么是忘了释放内存造成内存泄露,要么是多重释放造成了访问失败。甚至有些时候一个方法有多个返回语句的时候还要在每一个返回语句前释放一下内存。当时就在想为什么不能像Java一样有一个智能的垃圾回收器,来管理所有的内存呢。
这个痛点一直困扰到我开始学STL。原来STL早就考虑到手动释放内存的繁琐,所以提供了多种智能指针:, auto_ptr
unique_ptr
, shared_ptr
, weak_ptr
,并引入了“所有权”这个概念。大大简化了工程项目中的内存管理。也让我意识到我学的是假C++,真C(菜)。
所有权
单一所有权
两句话:所有权的拥有者有义务释放内存或转移所有权。同一时刻只会有一个所有权拥有者。
共享所有权
和用裸指针一样,所有权的拥有者不必负责释放内存,引用计数器会负责释放内存。同一时刻可以有多个所有权拥有者。
unique_ptr
重要的事情说三遍:
unique_ptr
不能被拷贝
unique_ptr
不能被拷贝
unique_ptr
不能被拷贝
unique_ptr
的所有者即为单一所有权的拥有者,因此它无法被拷贝。如果需要转移所有权,需要显示调用 move(unique_ptr)
来转移 或者 unqie_ptr.release()
方法放弃所有权。在生命周期结束时,若 unique_ptr
依然是所有权的拥有者,它会立刻释放掉对应的资源。示例:
unique_ptr<A> a = make_unique<A>(); unique_ptr<A> b = a; // can not assign unique_ptr to other unique_ptr unique_ptr<A> c(a); // can not copy unique_ptr unique_ptr<A> d(a.release()); // OK, a release the resource unique_ptr<A> e = move(a); // OK, a transfer ownership to e
与裸指针不同,单一所有权明确了资源的所有者,确定了资源该于何时被释放,增强了代码的可读性。当然,传递 unique_ptr
引用这种合法不合理的事也别干,要么直接 move
过去,要么只提供 unique_ptr.get()
但不转移所有权。
小惊喜:试试 std::set<unique_ptr>
,有惊喜。
shared_ptr
shared_ptr
在使用上更像裸指针,不同的地方就是它内部有一个引用计数器,记录了有多少共享所有权的拥有者。当计数归零,它会自动释放掉资源。它的优势是比 unique_ptr
更灵活,在很多需要共享资源的场景(比如多线程共享物件),它符合场景的需求。并且活用 shared_ptr
的最后走的人关门特性,在某些多线程应用的场景里可以实现会话结束通知,更新标记等功能。
彩蛋:
const unique_ptr<T> &
make the world a better place