1 shared_ptr禁止了隐式转换(explict),不能把一个指针赋值给shared_ptr. 例:shared_ptr<string> pNico = new string("nico");
2 make_shared初始化shared_ptr要比调用shared_ptr构造函数更快更安全,:shared_ptr<string> pJutta = make_shared<string>("jutta"); shared_ptr<string> pNico{new string("nico")};.因为前者只需要一次allocations,而后者需要两次,一次是指针指向的对象,一次是shared_ptr自身,
3 shared_ptr默认的deleter是 delete 而非delete[],因此当shared_ptr指向一个数组的时候需要自定义一个deleter.
std::shared_ptr<int> p(new int[10]); // ERROR, but compiles
std::shared_ptr<int> ptr(new int[10], [](int *p) { delete[] p; }); //ok
std::shared_ptr<int> ptr1(new int[10], std::default_delete<int[]>());//ok
4 shared_ptr虽然解决了内存管理的难题,但是也带来了新的问题,循环引用导致内存泄露,对于此可以用weak_ptr来解决。
5 不要把一个原始指针赋值多个shared_ptr组,因为这样会导致指针被delete对此,产生野指针。一定要理解下面两种写法的区别。对于unique_ptr也是同样的道理
int* p = new int;
shared_ptr<int> sp1(p);
shared_ptr<int> sp2(p); // ERROR: two shared pointers manage allocated int
shared_ptr<int> sp1(new int);
shared_ptr<int> sp2(sp1); // OK
6 当你需要把this指针转换为shared_ptr时不要直接转化,要继承std::enable_shared_from_this<>。下面的结果可以看到如果直接用this构造会导致多个shared_ptr 组指向一个指针,也就是5所说的问题
class RightFromThis: public std::enable_shared_from_this<RightFromThis>
{
public:
shared_ptr<RightFromThis> getSharedPtr()
{
return shared_from_this();
}
};
class WrongFromThis //error
{
public:
shared_ptr<WrongFromThis> getSharedPtr()
{
return shared_ptr<WrongFromThis>(this);
}
};
int
main()
{
shared_ptr<RightFromThis> shared_ptr1 = std::make_shared<RightFromThis>();
auto ptr1 = shared_ptr1->getSharedPtr();
shared_ptr<WrongFromThis> shared_ptr2 = std::make_shared<WrongFromThis>();;
auto ptr2 = shared_ptr2->getSharedPtr();
int shared_ptr1_use = shared_ptr1.use_count(); //2
int ptr1_use = ptr1.use_count(); //2
int shared_ptr2_use = shared_ptr2.use_count(); //1
int ptr2_use = ptr2.use_count(); //1
}
7 当一个指针依赖另外另一个指针时,我们可以用一个特殊的构造函数来解决。当我们调用标记1的代码时,就表示pi依赖于px当我们调用reset px并不会立即释放指针指向的对象,因为此时pi还在引用该指针。
class C
{
public:
~C(){
printf("~C\n");
}
int a;
};
class X
{
public:
~X(){
printf("~X\n");
}
C a;
};
int
main()
{
shared_ptr<X> px(new X);
shared_ptr<C> pi(px, &px->a); //标记1
px.reset();
printf("Done\n");
}
8 当shared_ptr指向一个void类型的指针,当我们需要转换指针类型时需要注意,当继承体系种的类型转换也是同样的。
shared_ptr<void> sp(new int); // shared pointer holds a void* internally
shared_ptr<int>(static_cast<int*>(sp.get())); // ERROR: undefined behavior
static_pointer_cast<int*>(sp); // OK
9 unique_ptr禁止copy,但是有move操作.
std::unique_ptr<ClassA> source()
{
std::unique_ptr<ClassA> ptr(new ClassA); // ptr owns the new object
...
return ptr; // move not copy
}
void g()
{
std::unique_ptr<ClassA> p;
for (int i=0; i<10; ++i)
{
p = source(); // p gets ownership of the returned object
// (previously returned object of f() gets deleted)
...
}
} // last-owned object of p ge
10 unique_ptr指向一个数组时,他的处理方式跟shared_ptr稍有不同,但是shared_ptr却不行,前者它调用的是unique_ptr的一个数组类型的模板特例class unique_ptr<_Tp[], _Dp>,它在释放内存时调用的是delete[],而shared_ptr没有提供class shared_ptr<_Tp[], _Dp>,因此shared_ptr是没有提供[]操作的。另外我们要为unique_ptr提供自定义的deleter时需要提供额外的模板参数,
std::unique_ptr<int[]> p(new int[10]); // OK call delete[]
std::unique_ptr<int> p(new int[10]); //ERROR runtime erroe,call delete
std::shared_ptr<int[]> p(new int[10]); // ERROR: does not compile
std::unique_ptr<int,void(*)(int*)> p(new int[10],[](int* p) {delete[] p;})
11 shared_ptr的性能问题,.unique_ptr针对性能和灵活性进行了优化.因为unique_ptr不能拷贝所以它本身qw e的内部结构是一个指针和一个delter指针,因此unique_ptr的性能跟普通的指针没有什么区别,并且更安全,易用,但是shared_ptr不同,shared_ptr不光需要这些,它还需要一个counter表示引用对象的数量甚至还需要另外一个counter来表示weak_ptr引用数量,即使没有shared_ptr在引用该对象,在所有的引用的weak_ptr销毁前,你也需要这个counter,并且为了保证counter的在多线程下可用性它是原子的,但是它在保证counter线程安全的同时也会丧失一些性能。在发生拷贝shared_ptr会比普通的指针慢很多。
12 线程安全问题,上面说了shared_ptr的counter是原子的,在多线程环境中传递shared_ptr时counter线程安全的,但是这并不表明shared_ptr是线程安全的,你可以把shared_ptr堪称一个对象,它的counter线程安全,但是它自己并不是线程安全的。
int
main()
{
shared_ptr<Class A> ptr = make_shared<Class A>();
weak_ptr<Class A> weak_ptr1(ptr);
int usecount1 = ptr.use_count();
int usecount2 = weak_ptr1.use_count();
{
/*Do something with usecount1 or usecoun .Not do that,
* usecount1 和 usecount2 并不是线程安全的,此时两个值也许在其他线程
* 已经被改了
* */
}
if(weak_ptr1.expired()) {
shared_ptr<X> sharedPtr = weak_ptr1.lock();
/*Do something with sharedPtr,not do that
* 此时sharedPtr一定不为null吗,不一定,如果你把ptr以引用的方式传递
* 到其他线程中,可能被reset了,
* */
if(sharedPtr) {
//如果sharedPtr没有传递到其他线程中去,这样应该是安全的
}
}
}
13 unique_ptr不需要任何开销。它们的“智能”基于特殊的构造函数和特殊的析构函数以及复制语义。对于无状态或空删除器unique_ptr应该消耗与普通指针相同的内存量,并且与使用普通指针和手动删除相比,应该没有运行时开销。但是,为了避免引入不必要的开销,您应该使用函数对象(包括lambdas)作为deleter,以便编译器理想情况下进行零开销的最佳优化。
14 在你不是百分百确定你暴漏出的原始指针会不会在其他地方被delete,特别是传入一些其他三方库时,或者不确定它会被修改(比如int *a = 0,int *b = 1,a = b),不要调用get方法暴漏原始指针,并且传递到别的地方。