new的行为
void* operator new(size_t sz) throw(); 源码位置:libsupc++/new_op.cc/
delete的行为
重载全局new delete/new[] delete[]
全局的影响很远
new[]下面所占的大小要额外加上一个计数器。
new -> void* operator new(xxx)
new[] -> void* operator new[](xxxx)
重载成员new delete/new[] delete[]
可以构建内存池??
c++实现高效内存池
重载new()/delete() placement new
new (yyy) xxx; -> void* operator new(xxx, xxx, xxx);重载的函数
根据placement argument(也就是yyy)可以有多个版本。其中yyy是一个指针的比较重要。
只要当new所调用的ctor抛出exception,才会调用这些重载版本的delete().它只可能这样被调用,主要用来清除未能完全创建成功的object所站用的memory。
一种形式:
的对象。原型中void*p
实际上就是指向一个已经分配好的内存缓冲区的的首地址。
我们知道使用new操作符分配内存需要在堆中查找足够大的剩余空间,这个操作速度是很慢的,而且有可能出现无法分配内存的异常(空间不够)。placement new就可以解决这个问题。我们构造对象都是在一个预先准备好了的内存缓冲区中进行,不需要查找内存,内存分配的时间是常数;而且不会出现在程序运行中途出现内存不足的异常。所以,placement new非常适合那些对时间要求比较高,长时间运行不希望被打断的应用程序。
下面这是另一种形式:
allocator类
将内存分配和对象构造分开。提供了一种类型感知的内存分配方法,它分配的内存是原始的、未构造的。
new不灵活呗,不灵活体现在内存分配和对象构造是一起的。
智能指针
不错的文章建议常看:
智能指针-使用 避坑和实现
c++智能指针最佳实践和源码分析
虽然对智能指针的概念比较熟悉了,但对具体的使用场景却不清楚。
主要是对所有权和生命周期的思考。
上面的一篇文章总结的不错:
unique_ptr使用场景:
简单的理解为:只在对象内部或方法内部使用的时候。
shared_ptr使用场景:
一般需要多个执行同一个对象的指针使用。
简单理解为:这个对象需要被多个class同时使用的时候。
weak_ptr使用场景
解决shared_ptr循环引用问题。
从面向对象的角度看:
组合关系- 在多线程中没问题,对象x的生命期由其唯一的拥有者控制。
比如,x是owner的直接数据成员,或者unique_ptr成员,或者owner持有的容器的元素。
关联关系-
聚合关系
有几个问题:
1.智能指针作为参数
智能指针作为参数,作为返回值,传递智能指针引用。
- unique_ptr传递const by refence可以阻止在函数中释放unique_ptr,也就是说只能使用(读、写) 但不会误释放。
- unique_ptr传值,没有拷贝赋值,需要move
- shared_ptr传引用
void f1(const std::unique_ptr<std::string> &p)
{
std::cout << "address: " << &p << " value: " << *p << "count: "
<< std::endl;
p = nullptr; //error
}
2.第三方库函数是裸指针但我使用的是智能指针??。
三种智能指针的API
#include <memory>
-
shared_ptr API
1.解引用(*, ->)
2.make_shared<T>(arg)
3.sp.get()
返回裸指针,最好不要用,就算要用也要确保不能delete
4.sp.use_count()
返回与p共享对象的智能指针个数,很慢
5.sp.unique()
是1返回true -
unique_ptr API
1.没有拷贝构造和拷贝赋值运算符,有一个例外那就是可以拷贝或赋值一个将要被销毁的unique_ptr(比如:从函数返回一个unique_ptr)
2.析构器的型别是智能指针型别的一部分(shared_ptr不是,二者差异很大)
3.up.release()
up放弃对指针的所有权,返回指针,并将up置空。可以实现转移所有权到另一个unique_ptr
4.up.reset(p)
p==空 or p != 空
5.解引用(*, ->)
6.unique_ptr是容易转换成shared_ptr的,注意shared_ptr接受一个右值。 -
weak_ptr API
一种不控制所指对象生命期的智能指针
1.要用一个shared_ptr来初始化
2.wp.use_count()
与wp共享对象的shared_ptr的数量
3.wp.reset()
将wp置空
4.由于对象可能不存在,不能直接通过weak_ptr直接访问对象,必须调用lock()。wp.lock()
:如果wp.use_cout() == 0返回空shared_ptr,否则返回一个指向wp的对象的shared_ptr
5.无法解引用
使用智能指针中的注意事项
很重要,非常重要
见effective c++部分
shared_ptr
- shared_ptr的尺寸是裸指针的两倍
- 引用计数的内存必须动态分配
- 引用计数的递增和递减是原子操作
源码分析
位置:shared_ptr以及weak_ptr -> include/tr1/shared_ptr.h
位置:unique_ptr -> include/bits/unique_ptr.h