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);