分类:c++| 发布时间:2015-10-20 00:48:00
在前面的文章中,我们实现了一个类似 std::auto_ptr
通过实现带有引用计数的指针指针可以解决这个问题。
下面通过 C++11 的 std::shared_ptr
#include <memory>
#include <iostream>
using namespace std;
void some_func()
{
shared_ptr<int> p1(new int(3));
shared_ptr<int> p2 = p1;
cout << "p1 pointer: " << hex << p1.get() << endl;
if (p1.get()) {
cout << "p1 value: " << *p1 << endl;
}
cout << "p2 pointer: " << hex << p2.get() << endl;
if (p2.get()) {
cout << "p2 value: " << *p2 << endl;
}
}
输出:
p1 pointer: 0x230b010
p1 value: 3
p2 pointer: 0x230b010
p2 value: 3
保存到 STL 容器中:
#include <vector>
#include <memory>
#include <iostream>
using namespace std;
void save_in_container()
{
vector<shared_ptr<int> > vec;
shared_ptr<int> p(new int(3));
vec.push_back(p);
shared_ptr<int> p2(new int(4));
vec.push_back(p2);
for (vector<shared_ptr<int> >::iterator i = vec.begin();
i != vec.end(); ++i) {
cout << **i << endl;
}
}
下面来看看如何实现带有引用计数的智能指针。
namespace MY_DEMO {
template<typename T>
class shared_ptr
{
public:
explicit shared_ptr(T *p = 0): p_(p), shared_count_(create_share_count()) {
}
shared_ptr(const shared_ptr<T> &rhs) {
rhs.inc();
this->p_ = rhs.p_;
this->shared_count_ = rhs.shared_count_;
}
~shared_ptr() {
dec();
}
void reset(T *p) {
if (this->get() == p)
return;
dec();
shared_count_ = create_share_count();
p_ = p;
}
T* get() {
return p_;
}
shared_ptr<T>& operator= (const shared_ptr<T> &rhs) {
if (rhs.shared_count_ != 0) {
rhs.inc();
this->dec();
this->shared_count_ = rhs.shared_count_;
this->p_ = rhs.p_;
} else {
this->dec();
this->shared_count_ = 0;
this->p_ = 0;
}
return *this;
}
bool operator! () const {
return !p_;
}
T& operator* () const {
return *p_;
}
T* operator-> () const {
return p_;
}
private:
void inc() const {
if (!shared_count_)
return;
++*shared_count_;
}
void dec() {
if (!shared_count_)
return;
if (!(--*shared_count_)) {
delete shared_count_;
shared_count_ = 0;
if (p_) {
delete p_;
p_ = 0;
}
}
}
int* create_share_count() {
int *tmp = new int(1);
return tmp;
}
private:
T *p_;
mutable int *shared_count_;
};
} // namespace MY_DEMO
带引用计数的智能指针通过共享一个引用计数器(在我们的实现中是 shared_count_) 来跟踪一共有多少个智能指针引用到了这个原始指针。 在拷贝构造函数或者赋值运算时将右值的引用计数加 1,然后将自身的引用计数减 1。 在构造函数中将引用计数置为 1,析构时将引用计数减 1。 当引用计数为 0 时,删除引用计数以及保存的原始指针。
下面我们来测试下我们实现的智能指针是否如我们预期地工作。
首先,在 shared_ptr 上添加一些输出:
namespace MY_DEMO {
#include <iostream>
#include <string>
using namespace std;
template<typename T>
class shared_ptr
{
public:
// See other impl above
explicit shared_ptr(T *p = 0): p_(p), shared_count_(create_share_count()) {
cout << "shared_ptr default constructor" << endl;
}
shared_ptr(const shared_ptr<T> &rhs) {
cout << "shared_ptr copy constructor" << endl;
rhs.inc();
this->p_ = rhs.p_;
this->shared_count_ = rhs.shared_count_;
}
~shared_ptr() {
cout << "shared_ptr destructor" << endl;
dec();
}
void reset(T *p) {
cout << "shared_ptr reset" << endl;
if (this->get() == p)
return;
dec();
shared_count_ = create_share_count();
p_ = p;
}
shared_ptr<T>& operator= (const shared_ptr<T> &rhs) {
cout << "shared_ptr operator=" << endl;
if (rhs.shared_count_ != 0) {
rhs.inc();
this->dec();
this->shared_count_ = rhs.shared_count_;
this->p_ = rhs.p_;
} else {
this->dec();
this->shared_count_ = 0;
this->p_ = 0;
}
return *this;
}
void dump() {
cout << "value = " << *p_ << endl;
cout << "shared_count_ = " << *shared_count_ << endl;
}
private:
void inc() const {
if (!shared_count_)
return;
++*shared_count_;
cout << "inc shared_count_ " << *shared_count_ << endl;
}
void dec() {
if (!shared_count_)
return;
if (!(--(*shared_count_))) {
cout << "dec shared_count_ " << *shared_count_ << endl;
delete shared_count_;
shared_count_ = 0;
if (p_) {
delete p_;
p_ = 0;
}
} else {
cout << "dec shared_count_ " << *shared_count_ << endl;
}
}
}
} // namespace MY_DEMO
using MY_DEMO::shared_ptr;
void test_copy_constructor()
{
cout << "begin test_copy_constructor" << endl;
shared_ptr<int> p1(new int(3));
shared_ptr<int> p2(p1);
cout << "p1 dump:" << endl;
p1.dump();
cout << "p2 dump:" << endl;
p2.dump();
cout << "end test_copy_constructor" << endl;
}
输出为:
begin test_copy_constructor
shared_ptr default constructor
shared_ptr copy constructor
inc shared_count_ 2
p1 dump:
value = 3
shared_count_ = 2
p2 dump:
value = 3
shared_count_ = 2
end test_copy_constructor
shared_ptr destructor
dec shared_count_ 1
shared_ptr destructor
dec shared_count_ 0
首先我们通过默认的构造函数创建了 p1,然后将 p1 拷贝给 p2, 此时引用计数为 2。 然后退出 test_copy_constructor,调用 p2 的析构函数,引用计数减 1, 此时引用计数为 1,调用 p1 的析构函数,引用计数减 1, 此时引用计数为 0,删除引用计数以及原始指针。
using MY_DEMO::shared_ptr;
void test_assign()
{
cout << "begin test_assign" << endl;
shared_ptr<int> p1(new int(3));
shared_ptr<int> p2;
p2 = p1;
cout << "p1 dump:" << endl;
p1.dump();
cout << "p2 dump:" << endl;
p2.dump();
cout << "end test_assign" << endl;
}
输出为:
begin test_assign
shared_ptr default constructor
shared_ptr default constructor
shared_ptr operator=
inc shared_count_ 2
dec shared_count_ 0
p1 dump:
value = 3
shared_count_ = 2
p2 dump:
value = 3
shared_count_ = 2
end test_assign
shared_ptr destructor
dec shared_count_ 1
shared_ptr destructor
dec shared_count_ 0
首先我们通过默认的构造函数创建了 p1,p2。 然后将 p1 赋值 p2,此时 p1 引用计数为 2, p2 本来的引用计数为 0,删除本来的引用计数以及原始指针, 将 p1 的引用计数以及原始指针赋给 p2。 然后退出 test_copy_constructor,调用 p2 的析构函数,引用计数减 1, 此时引用计数为 1,调用 p1 的析构函数,引用计数减 1, 此时引用计数为 0,删除引用计数以及原始指针。
using MY_DEMO::shared_ptr;
void test_reset()
{
cout << "begin test_reset" << endl;
shared_ptr<int> p1(new int(3));
int *tmp = new int(6);
p1.reset(tmp);
p1.reset(tmp);
p1.dump();
cout << "end test_reset" << endl;
}
输出为:
begin test_reset
shared_ptr default constructor
shared_ptr reset
dec shared_count_ 0
shared_ptr reset
value = 6
shared_count_ = 1
end test_reset
shared_ptr destructor
dec shared_count_ 0
通过默认构造函数创建 p1,然后创建原始指针 tmp, 第一次将 tmp 设置给 p1 时 p1 原来的引用计数减 1, 此时原来的引用计数为 0,删除原来的引用计数以及原始指针。 创建新的引用计数,并将原始指针设置为 tmp。 再次将 tmp 设置给 p1,此时由于 tmp 与 p1 保存的原始指针是 同一个指针,直接退出 reset 。 然后就是退出 test_reset,p1 析构。
using MY_DEMO::shared_ptr;
void test_save_in_vector()
{
cout << "begin test_save_in_vector" << endl;
vector<shared_ptr<int> > vec;
shared_ptr<int> p1(new int(3));
vec.push_back(p1);
cout << "p1 dump:" << endl;
p1.dump();
cout << "end test_save_in_vector" << endl;
}
输出为:
begin test_save_in_vector
shared_ptr default constructor
shared_ptr copy constructor
inc shared_count_ 2
p1 dump:
value = 3
shared_count_ = 2
end test_save_in_vector
shared_ptr destructor
dec shared_count_ 1
shared_ptr destructor
dec shared_count_ 0
可以正常保存到 std::vector 中。