shared_ptr三个陷阱

来源:互联网 发布:sqlserver报表 编辑:程序博客网 时间:2024/05/20 05:58
shared_ptr 存储一个指向动态分配对象的指针。在最后一个 shared_ptr 所指向的对象被销毁或重置时,要保证它所指向的对象被删除

1. shared_ptr不能多次引用同一原始指针

错误:当p1,p2离开作用域时,由于p1,p2的引用计数都为0,会导致两次释放同一块内存
#include <iostream>
#include <tr1/memory>
using std::tr1::shared_ptr;
using std::cout;
using std::endl;

int main()
{
        int *tmp = new int(10);
        shared_ptr<int> p1(tmp);
        cout << "the ref count of p1: " << p1.use_count() << endl;
        shared_ptr<int> p2(tmp);
        cout << "the ref count of p1: " << p1.use_count() << "\t the ref count of p2: " << p2.use_count() << endl;

        return 0;
}

output:

the ref count of p1: 1
the ref count of p1: 1 the ref count of p2: 1
*** glibc detected *** ./main: double free or corruption (fasttop): 0x0000000000f97010 ***
----------------------------------------------------
正确:使用最初的shared_ptr实例拷贝来维护对象生存期
#include <iostream>
#include <tr1/memory>
using std::tr1::shared_ptr;
using std::cout;
using std::endl;

int main()
{
        shared_ptr<int> p1(new int(10));
        cout << "the ref count of p1: " << p1.use_count() << endl;
        shared_ptr<int> p2(p1);
        cout << "the ref count of p1: " << p1.use_count() << "\t the ref count of p2: " << p2.use_count() << endl;

        return 0;
}

output:

the ref count of p1: 1
the ref count of p1: 2 the ref count of p2: 2

2. shared_ptr不能包装this

错误:直接包装this
#include <iostream>
#include <tr1/memory>
using std::tr1::shared_ptr;
using std::cout;
using std::endl;

class foo
{
public:
        shared_ptr<foo> get()
        {
                return shared_ptr<foo>(this);
        }
};

int main()
{
        shared_ptr<foo> p1(new foo);
        cout << "the ref count of p1: " << p1.use_count() << endl;
        shared_ptr<foo> p2 = p1->get();
        cout << "the ref count of p1: " << p1.use_count() << "\t the ref count of p2: " << p2.use_count() << endl;

        return 0;
}

output:

the ref count of p1: 1
the ref count of p1: 1 the ref count of p2: 1
*** glibc detected *** ./main: double free or corruption (fasttop): 0x00000000021e1010 ***

正确:使用shared_from_this

shared_from_this()是enable_shared_from_this<T>的成员函数,返回shared_ptr<T>
enable_shared_from_this::weak_ptr并不在构造函数中设置,而是在shared_ptr<T>的构造函数中设置,
所以,shared_from_this()必须在shared_ptr<T>的构造函数被调用之后才能使用

Every enable_shared_from_this base contains a weak_ptr, 
the shared_ptr constructor looks up the enable_shared_from_this base and initializes its weak_ptr accordingly. 
This doesn't work when there are two or more enable_shared_from_this bases, though. 

#include <iostream>
#include <tr1/memory>
using std::tr1::shared_ptr;
using std::cout;
using std::endl;

class foo : public std::tr1::enable_shared_from_this<foo>
{
public:
        shared_ptr<foo> get()
        {
                return shared_from_this();
        }
};

int main()
{
        shared_ptr<foo> p1(new foo);
        cout << "the ref count of p1: " << p1.use_count() << endl;
        shared_ptr<foo> p2 = p1->get();
        cout << "the ref count of p1: " << p1.use_count() << "\t the ref count of p2: " << p2.use_count() << endl;

        return 0;
}

output:

the ref count of p1: 1
the ref count of p1: 2 the ref count of p2: 2

执行shared_ptr<foo> p1(new foo)做了3个动作,首先,调用enable_shared_from_this的构造函数;其次,调用foo的构造函数;最后,调用shared_ptr的构造函数

3.多线程对同一个share_ptr执行写操作是不安全的,共享引用计数的不同的shared_ptr被多线程写是线程安全的
共享引用计数如下:

include <iostream>
#include <tr1/memory>
#include <pthread.h>
using std::tr1::shared_ptr;
using std::cout;
using std::endl;

shared_ptr<int> spKey(new int(9999));

shared_ptr<int> doSomething(shared_ptr<int> &param)
{
        shared_ptr<int> sp(param); // sp and param share the same ref count
        // do something to change sp
        shared_ptr<int> tmp(new int(0));
        //cout << "before swap, sp ref count: " << sp.use_count() << "\t\ttmp ref count" << tmp.use_count() << endl;
        sp.swap(tmp);
        tmp.swap(sp);
        //cout << "after swap, sp ref count: " << sp.use_count() << "\t\ttmp ref count" << tmp.use_count() << endl;

        return sp;
}

void *run(void *param)
{
        for (int i = 0; i < 10000; ++i)
        {
                shared_ptr<int> tmp = doSomething(spKey);
                if (9999 != *tmp)
                {
                        cout << "not safe......" << endl;
                        break;
                }
        }
        cout << "quit....." << endl;

        return NULL;
}

int main()
{
        int i, num = 5;
        pthread_t threads[5];
        for (i = 0; i < num; ++i)
                pthread_create(&threads[i], 0, run, NULL);
        for (i = 0; i < num; ++i)
                pthread_join(threads[i], 0);

        return 0;

}

output:

g++ shared_ptr-test.cpp -o main -pthread
./main 

quit.....
quit.....
quit.....
quit.....
quit.....



0 0
原创粉丝点击