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