- RAII和auto_ptr
- 使用unique_ptr 管理排他性资源
- 使用shared_ptr
- weak_ptr
- 使用
make_shared<>,make_unique<>
- pimpl使用技巧
- 补充shared_ptr 控制块实现引用计数,
enable_shared_from_this<Item>
实现
RAII和auto_ptr
RAII Resource Acquisition Is Initialization
资源获取即时初始化
http://baike.baidu.com/link?url=c5E3AKpcarKiTYoEntcAit9F-A2MgyixfLWH1N8dk9yc6fItSJPkIsFgD4Ac7BJhuvMi8A3HPda3-nPzRtRJKK
http://www.jellythink.com/archives/101
避免使用裸指针
观察者模式
class Obesrver {
public:
void observe(observable* po){
_subject = po;
po->register(this);
}
virtual ~Observer(){
_subject->unregister(this);
}
virtual void notify(void)=0;
};
class observable{
public:
void register(Observer* po);
void unregister(Observer* po);
void notify(){
for (Observer*po:_observers){
po->notify;
}
}
protected:
vector<Observer*> _observers;
};
问题 当多线程时无法得知 vector中的Observer* 是否有效。是否已经被释放.
多线程程序执行顺序不能保证。
总结内存管理问题
1. 缓冲区溢出 例如,字符串访问越界,避免方法不要手动管理,要用容器。
2. 空悬指针(野指针)用智能指针解决
3. 重复释放,会发生不可预知行为,用智能指针解决
4. 内存泄漏,用智能指针解决
5. new[]/delete不配对 避免方法不要手动管理,要用容器。
RAII Resource Acquisition is initialization
在对象构造时就获得资源,在对象生命周期中资源始终有效,对象释放时才释放资源。
auto_ptr 在栈上创建可以在生命周期到期时自动析构,并且释放new出来的空间。
例如,
void func(void) {
auto_ptr<Item> ptr(new Item);
}
auto_ptr的问题,他的复制构造,和拷贝构造函数有问题
例1
int main(void){
auto_ptr<int> p1(new int(100))
auto_ptr<int> p2 = p1;//此时p1指向空,将控制权交给p2
}
例2
int main(void) {
int* pi = new int(100);
auto_ptr<int> p1(pi);
auto_ptr<int> p2(pi);//这样虽然p1,p2可以都拥有该资源的控制权,但是当函数只进行结束释放pi时也会释放两次。
}
使用unique_ptr 管理排他性资源
例1
unique_ptr<Item> p(new Item);
unique_ptr<Item> p2 = p;//编译报错,unique_ptr 具有排他性
//若想要转移资源管理必须使用move
unique_ptr<Item> p3 = move(p);//此时p失去资源。
自定义删除器
1.lambda
2.函数指针
3.functor
lambda删除器
auto delItem = [](Item* pItem){
delete pItem;
}
int main(void) {
unique_ptr<Item,decltype(delItem)> p(nullptr,delItem);
p.reset(new Item);//sizeof(p) =4;对p没有影响
}
函数指针删除器
void delItem(Item* p){
delete p;
}
int main(void) {
unique_ptr<Item,void(*)(Item*)> p(nullptr,delItem);
p.reset(new Item);//sizeof(p) = 8 需要一个函数指针来记录函数位置所以变大
}
仿函数删除器
class DelItem {
public:
void operator()(Item* p) {
delete p;
}
};
int main(){
unique_ptr<Item,DelItem> p(nullptr,DelItem);
p.reset(new Item);//sizeof(p),此时p 的size 由 DelItem决定,空的话为4 ,DelItem有几个变量就加上变量大小。
}
优先使用lambda表达式,其次functor,函数指针不推荐因为c方式。
unique_ptr 使用时尽量显式执行不要隐式。
unique_ptr<int> p(new int);//要这样
unique_ptr<int> p = new int;//不要这样,防止隐式转化。
unique_ptr可以转化为shared_ptr
int main(){
unique_ptr<Item> up(new Item(1,2));
shared_ptr<Item> sp = move(up);//此时up指向空
}
不要直接管理数组,交给容器。声明数组的方法:
unique_ptr<int[]> foo (new int[5]);
将unique_ptr 放入容器中,严格来讲是不允许的
但是可以使用move
unique_ptr<int> sp(new int(1));
vector<unique_ptr<int>> vec;
vec.push_back(std::move(sp));
unique_ptr<Item[]> p(new)
使用shared_ptr
int* pi = new int(100);
unique_ptr<int> p1(pi);
unique_ptr<int> p2(pi);//和auto_ptr 一样会两次释放
int* pi = new int(100);
shared_ptr<int> p1(pi);
shared_ptr<int> p2(pi);//和auto_ptr 一样会两次释放
//shared_ptr管理类级对类内返回this的无法管理
shared_ptr<Item> p1 (new Item);
shared_ptr<Item> p2 = p1->get_shared_ptr();
//解决方法集成一个shared_from_this<Item>
class Item:public enable_shared_from_this<Item>{
shared_ptr<Item> get_shared_ptr(void){
return sahred_from_this();//此时不会丢失控制块信息
}
};
shared_ptr<Item> p1 (new Item);
shared_ptr<Item> p2 = p1->get_shared_ptr();
此时 若Item* p1 = new Item;会出错由于p1不是shared_ptr ,shared_from_this()找不到控制块失败
所以此处应该禁止用户使用默认构造,应该使用一个工厂方法来构造
class Item:public enable_shared_from_this<Item> {
public:
static shared_ptr<Item> creatItem(){
return shared_ptr<Item>(new Item);//使用 make_shared<> 代替
}
shared_ptr<Item> get_shared_ptr(void){
return shared_from_this();//此时不会丢失控制块信息
}
protected:
item(){}
};
shared_ptr<Item> p = Item::creatItem();
weak_ptr
解决互相引用问题
class ItemA {
public:
ItemA(){cout << "ItemA default cotr" <<endl;}
~ItemA(){cout << "ItemA default decotr" <<endl;}
void set(shared_ptr<ItemB> &pb) {_pb = pb;}
private:
shared_ptr<ItemB> _pb;//->weak_ptr<ItemB> _pb;
};
calss ItemB{
public:
ItemB(){cout << "ItemA default cotr" <<endl;}
~ItemB(){cout << "ItemA default decotr" <<endl;}
void set(shared_ptr<ItemA> &pa) {_pa = pa;}
private:
shared_ptr<ItemA> _pa;//->weak_ptr<ItemA> _pa;
};
shared_ptr<ItemA> pa(new ItemA);
shared_ptr<ItemB> pb(new ItemB);
pa->set(pb);
pb->set(pa);
此时构成相互引用构成死锁,最后两个对象都无法析构
这时要改成weak_ptr
weak_ptr不能创建只能依附shared_ptr
解引用weak_ptr 很危险不能确定关联的shared_ptr 是否存在,使用时将其提升为shared_ptr
例如
shared_ptr<int> sp(new int(100));
weak_ptr<int> wp = sp;
if(wp.expired)
else:
shared_ptr<int> sp2 = wp.lock();//生成强引用
cout <<*sp2 << endl;
使用make_shared<>,make_unique<>
好处
1.避免代码重复
shared_ptr<int> sp = make_shared<int>();
auto sp = make_shared<int>();
2.确保异常内存泄漏保证 new和shared_ptr构造在一起,不会分开
例如
void func (shared_ptr<Item>(new Item), process() )
shared_ptr<Item>(new Item)
会先new空间再调用构造函数若此时process() 有异常发生,则不能保证 new出来的空间会被正确释放。
3.效率更高
因为传统 shared_ptr<int> p(new int)
,会调用两次动态内存分配,一次分配new一次分配控制块
使用make_shared 可以一次分配。 但是写了自己的删除器的时候没法使用make_shared。
pimpl使用技巧
pimpl 即pointer to implementation
原模式
CTeam::Impl Item {
Item();
~Item();
void setName(String& name);
void setContent(const String& content);
protected:
string _name;
string _content;
};
使用pimpl
struct Impl{
string _name;
string _content
}
class Item {
Item();
~Item();
void setName(String& name);
void setContent(const String& content);
protected:
struct Impl;
unique_ptr<Impl> _pImpl;
};
1.提高编译效率 point to implimentation
将struct内容实现在cpp文件中,当成员变量需要更改时仅需要编译cpp文件
2.隐藏成员变量细节
参考:
http://blog.csdn.net/newyher/article/details/40047241
http://www.oschina.net/translate/best-friends-cpp11-move-semantics-and-pimpl
http://blog.csdn.net/suwei19870312/article/details/7522191
http://blog.csdn.net/lihao21/article/details/47610309
补充shared_ptr 控制块实现引用计数, enable_shared_from_this<Item>
实现
参考:
https://my.oschina.net/costaxu/blog/103119
enable_shared_from_this<Item>
实现:
template<typename _Tp>
class enable_shared_from_this
{
protected:
constexpr enable_shared_from_this()noexcept{}
enable_shared_from_this(const enable_shared_from_this&)noexcept {}
// and assignment operator ctor;...
public:
shared_ptr<_Tp>
shared_from_this()
{return shared_ptr<_Yp>(this->_M_weak_this);}
shared_ptr<_Tp>
shared_from_this() const
{return shared_ptr<_Yp>(this->_M_weak_this);}
private:
template<typename _Tp1>
void
_M_weak_assign(_Tp1* __p,const __shared_count<>& __n)const noexcept
{_M_weak_this._M_assign(__p,__n);}
mutable weak_ptr<_Tp> _M_weak_this;
};
_M_weak_assign 会将计数传递给weak_ptr<_Tp> _M_weak_this
。