c++ 11 5

  • 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值