您的位置:首页 > 编程语言 > C语言/C++

C++ primer 薄片系列之 智能指针

2017-11-02 14:35 204 查看

shared_ptr

引用次数和交换操作

std::shared_ptr<A> a(new A);
std::cout << a.use_count() << std::endl; //  输出 1
std::shared_ptr<A> b;
std::cout <<  b.use_count() << std::endl; //  输出 0
a.swap(b);
std::cout << a.use_count() << std::endl; //  输出 0
std::cout <<  b.use_count() << std::endl;//  输出 1


reset 相关操作

std::shared_ptr<int> b(new int);
b.reset() //reset释放对象
b.reset(new int) //b 指向新的对象

b.reset(q,d)//调用d 而不是delete 去释放q
std::shared_ptr<A> a(new A);
a.reset(new A, [](A*){std::cout << "I do nothing" << std::endl;});//  使用新的lambda表达式而不是delete去释放,这里a的reset后的新对象,并没有释放


unique_ptr

它的reset 没有shared_ptr中的reset(p,d)操作, 即不能在reset 函数中传递删除器,只能在实例化模板时提供删除器

std::shared_ptr<A> a;
if(!a)
{
std::cout << "a is empty" << std::endl;
}
std::unique_ptr<A> b(new A);
a.reset(b.release());// b放弃对指针的控制权,返回指针给 a.reset做参数,b置空
if(!b)
{
std::cout << "b is empty" << std::endl;
}

std::unique_ptr<A> b(new A);
b.reset(nullptr);//OR b.reset() 均可使b置空
if(!b)
{
std::cout << "b is empty" << std::endl;
}

std::unique_ptr<A> b(new A, [](A*){std::cout << "我代替了delete操作" << std::endl;}); // 错误, unique_ptr reset没有重载这个函数
std::unique_ptr<A,void(*)(A*)> s(new A, [](A*){std::cout << "I do nothing" << std::endl;});// 只能在unique_ptr实例化的时候,提供模板参数,这里采用了lambda表达式。也可以使用函数
void delFunc(A *)
{
std::cout << "I do nothing" << std::endl;
}
std::unique_ptr<A,decltype(delFunc)*> s2(new A,delFunc);


—管理动态数组

unique_ptr<A[]>  up(new A[]);
up在作用域结束后,会自动调用delete[] ,释放动态数组。
访问动态数组中的元素时,可以直接 up[i]  的形式

shared_ptr则必须制定动态数组删除器
shared_ptr< A > sh(new A[10]); //严重bug
std::shared_ptr< A> sp(new A[10],[](A *p){delete[] p;});//必须定义删除器
访问动态数组的元素时,只能以 *(sh.get()+i)的方式获取 sh内置动态数组中的元素


weak_ptr

w.use_count()

w.expired() use_count == 0 时为true,否则false

w.lock() expired 为true时返回空shared_ptr否则返回指向w的对象的shared_ptr

避免循环引用

class B;
class A
{
public:
shared_ptr<B> pb;
};
class B
{
public:
shared_ptr<A> pa;
};
{
shared_ptr<A> a(new A);
shared_ptr<B> b(new B);
a->pb = b;//b.use_count() == 2
b->pa = a;//a.use_count() == 2
}
a和b离开作用域, 释放B,导致b的引用次数除掉1,此时b所指的内存引用次数为2-1 = 1,同样a所指向的内存的引用次数也是2-1 = 1,从 a和b所指向的内存不能析构,形成了内存泄露。
此时需要把 pa换成 weak_ptr<A>, pb 换成 weak_ptr<B>, OK了。


Allocator

这玩意存在的理由在于, new的负担太重了,它完成了内存分配和对象构造两件事情。为了分离这两件事情,所以就有了它。

class A
{
A(){}
~A(){}

};
std::allocator<A> alloc;
auto p = alloc.allocate(10); // 此时A的构造函数不会被调用
auto q = p;
alloc.construct(q++);
while (q != p)
{
alloc.destroy(--q);
}
alloc.deallocate(p, 10);

std::allocator<A> alloc;
auto p = alloc.allocate(10);
拷贝和填充未初始化内存的算法
std::uninitialized_copy(s.begin(),s.end(), p); // 调用A的拷贝构造函数
std::uninitialized_copy_n(s.begin(), 2, p); // 拷贝构造2个A 到p
A data;
std::uninitialized_fill(p,p+2, data);//填充data的拷贝到原始内存
std::uninitialized_fill_n(p,2, data);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++primer
相关文章推荐