先看一个例子:
#include <stdio.h>
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
A() { printf("A constructor\n"); }
~A() { printf("A destructor\n"); }
void Print() { printf("This is A\n"); }
};
int _tmain(int argc, _TCHAR* argv[])
{
shared_ptr<A> a(new A());
shared_ptr<A> b(new A());
a = b;
getchar();
return 0;
}
运行结果如下:
A constructor
A constructor
A destructor
上面的例子中创建了共享指针a和b,引用计数都是1,b赋值给a,此时a最初所指对象会被销毁,因为它的引用计数变为0,b所指的对象引用计数加1
另一个例子:
#include <stdio.h>
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class A
{
public:
A() { printf("A constructor\n"); }
~A() { printf("A destructor\n"); }
void Print() { printf("This is A\n"); }
};
void SP()
{
A* p = new A();
shared_ptr<A> a(p);
shared_ptr<A> b(p);
printf("a.use_count(): %d, b.use_count(): %d\n", a.use_count(), b.use_count());
}
int _tmain(int argc, _TCHAR* argv[])
{
SP();
getchar();
return 0;
}
运行结果如下:
A constructor
a.use_count(): 1, b.use_count(): 1
A destructor
A destructor
注意:上面代码运行输出以上结果后,还会弹出错误异常窗口
可以看出,a和b都关联到了p上,并且a和b的引用计数也是单独算的,都是1,这就导致函数退出的时候把p指向的对象销毁了两次,导致错误发生。
接着看例子:
#include <stdio.h>
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class A
{
public:
A() { printf("A constructor\n"); }
~A() { printf("A destructor\n"); }
void Print() { printf("This is A\n"); }
};
int _tmain(int argc, _TCHAR* argv[])
{
shared_ptr<A> a(new A());
A* p = a.get();
p->Print();
printf("a.use_count(): %d\n", a.use_count());
getchar();
return 0;
}
运行结果如下:
A constructor
This is A
a.use_count(): 1
share_ptr的成员函数get可以获取传统的C指针,此时引用计数仍然是1,不要对获取到的传统c指针进行delete操作,否则会发生错误
接下来的例子:
#include <stdio.h>
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class A
{
public:
A() { printf("A constructor\n"); }
~A() { printf("A destructor\n"); }
void Print() { printf("This is A\n"); }
};
int _tmain(int argc, _TCHAR* argv[])
{
shared_ptr<A> a(new A());
shared_ptr<A> b(a);
shared_ptr<A> c(b);
printf("a.use_count(): %d\n", a.use_count());
printf("b.use_count(): %d\n", b.use_count());
printf("c.use_count(): %d\n", c.use_count());
a.reset();
printf("\nAfter a.reset()\n");
printf("a.use_count(): %d\n", a.use_count());
printf("b.use_count(): %d\n", b.use_count());
printf("c.use_count(): %d\n", c.use_count());
getchar();
return 0;
}
运行结果如下:
A constructor
a.use_count(): 3
b.use_count(): 3
c.use_count(): 3
After a.reset()
a.use_count(): 0
b.use_count(): 2
c.use_count(): 2
调用reset后,a就不再跟之前绑定的指针有任何关系了(实际过程是a的内部成员变量_Ptr和_Rep都被置为0,通过创建临时变量再Swap),所以引用b和c的引用计数也都相应减1
make_shared的使用:
#include <stdio.h>
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class A
{
public:
A() { printf("A constructor\n"); }
A(int a): m_a(a) { printf("A constructor param\n"); }
~A() { printf("A destructor\n"); }
void Print() { printf("This is A\n"); }
int m_a;
};
int _tmain(int argc, _TCHAR* argv[])
{
shared_ptr<A> d = make_shared<A>();
shared_ptr<A> e = make_shared<A>(1);
d->Print();
e->Print();
getchar();
return 0;
}
运行结果:
A constructor
A constructor param
This is A
This is A
Q: 为什么要尽量使用 make_shared()?
A: 为了节省一次内存分配,原来 shared_ptr<A> x(new A); 需要为 A 和 ref_count 各分配一次内存,现在用 make_shared() 的话,可以一次分配一块足够大的内存,供 A 和 ref_count 对象容身。不过 A 的构造函数参数要传给 make_shared(),后者再传给 A::A()。
shared_ptr有两种类型转换函数,一个是static_pointer_cast, 一个是dynamic_pointer_cast,用法和static_cast和dynamic_cast很像。
看如下例子:
#include <stdio.h>
#include <memory>
using namespace std;
class A
{
public:
A() { printf("A constructor\n"); }
~A() { printf("A destructor\n"); }
virtual void VFun() {}
};
class B: public A
{
public:
B() { printf("B constructor\n"); }
~B() { printf("B destructor\n"); }
void VFun() {}
};
int _tmain(int argc, _TCHAR* argv[])
{
shared_ptr<A> a = shared_ptr<B>(new B());
printf("a.get(): %p\n\n", a.get());
shared_ptr<B> b = dynamic_pointer_cast<B>(shared_ptr<A>(new A()));
printf("b.get(): %p\n\n", b.get());
shared_ptr<B> c = dynamic_pointer_cast<B>(a);
printf("c.get(): %p\n\n", c.get());
getchar();
return 0;
}
运行结果如下:
A constructor
B constructor
a.get(): 0066AEE8
A constructor
A destructor
b.get(): 00000000
c.get(): 0066AEE8
dynamic_pointer_cast下行转换基类必须有虚函数成员
#include <stdio.h>
#include <memory>
using namespace std;
class A
{
public:
A() { printf("A constructor\n"); }
~A() { printf("A destructor\n"); }
};
class B: public A
{
public:
B() { printf("B constructor\n"); }
~B() { printf("B destructor\n"); }
};
int _tmain(int argc, _TCHAR* argv[])
{
shared_ptr<B> b = static_pointer_cast<B>(shared_ptr<A>(new A()));
printf("b.get(): %p\n", b.get());
b.reset();
printf("\n");
shared_ptr<A> a = static_pointer_cast<A>(shared_ptr<B>(new B()));
printf("a.get(): %p\n", a.get());
a.reset();
getchar();
return 0;
}
运行结果如下:
A constructor
b.get(): 0049AEE8
A destructor
A constructor
B constructor
a.get(): 0049AEE8
B destructor
A destructor