c++ 11 5
来源:互联网 发布:程序员没前途 编辑:程序博客网 时间:2024/06/16 12:23
- 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的问题,他的复制构造,和拷贝构造函数有问题
例1int main(void){ auto_ptr<int> p1(new int(100)) auto_ptr<int> p2 = p1;//此时p1指向空,将控制权交给p2}例2int main(void) { int* pi = new int(100); auto_ptr<int> p1(pi); auto_ptr<int> p2(pi);//这样虽然p1,p2可以都拥有该资源的控制权,但是当函数只进行结束释放pi时也会释放两次。}
使用unique_ptr 管理排他性资源
例1unique_ptr<Item> p(new Item);unique_ptr<Item> p2 = p;//编译报错,unique_ptr 具有排他性//若想要转移资源管理必须使用moveunique_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_ptrint 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 放入容器中,严格来讲是不允许的但是可以使用moveunique_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
。
- c语言 11-5
- C(11)
- 11C
- C++(5)
- C.5
- c++(5)
- C/C++(5)printk函数
- 2017-5-11 C++primer笔记
- [C/C++][2012-11-29] __attribute__ 详解
- 11-22C/C++/python程序编程
- 11/24 C/C++/Python程序bainchen
- 高质量C++/C编程指南[5]
- C/C++/C#面试题(5)
- 娓娓道来c指针 (5)c数组本质
- [C/C++] 算法提高 5-3日历
- 5C?5S?
- c练习11
- C语言例题11:
- C++ const 和static 区别
- JDBC
- hdu-3183(贪心+RMQ)
- PyTorch读取Cifar数据集并显示图片
- SpringBoot+Mybatis+druid(基于maven)
- c++ 11 5
- Java Web项目中使用Freemarker生成Word文档
- 【项目记录】山东大学场馆管理系统之——场馆申请管理
- echarts 简单使用
- C#异常捕捉处理
- angular学习之——ng-show/ng-hide与ng-if的区
- 2017 计蒜之道 初赛 第四场 (计蒜课比赛)第一题
- 巧用方式提升查询效率
- Tomcat中JVM内存溢出问题(centos)