1. 程式人生 > >[C++11]_[初級]_[shared_ptr的使用場景]

[C++11]_[初級]_[shared_ptr的使用場景]

場景

  1. C++11之前,使用auto_ptr只能適用於 new 出來的物件,為此我還專門建立了一些工具類來釋放物件.使用智慧指標的方式釋放malloc出來的堆空間,C++11出現後可以使用shared_ptr來管理C指標了.

  2. 多執行緒程式經常會遇到在某個執行緒A建立了一個物件,這個物件需要線上程B使用,在沒有shared_ptr時,因為執行緒A,B結束時間不確定,即在A或B執行緒先釋放這個物件都有可能造成另一個執行緒崩潰,所以為了省時間一般都是任由這個記憶體洩漏發生.當然也可以經過複雜的設計,由一個監控執行緒來統一刪除,但這樣會增加程式碼量和複雜度.這下好了,shared_ptr 可以方便的解決問題,因為它是引用計數和執行緒安全的.

參考

說明

shared_ptr的所有的方法(包括複製建構函式 和 賦值過載)都能被多執行緒中的不同shared_ptr例項(擁有相同的物件)安全的呼叫而不需要額外的同步操作.

使用

建立方式

// 方式1,使用 make_shared 支援不定引數
auto sp = std::make_shared<B>(12,13);

struct D
{
    void operator()(void* data)
    {
        std::cout << "free: " << (int*)data << std
::endl; free(data); } }; A* a = (A*)malloc(sizeof(A)); a->i = 10; std::cout << (int*)a << std::endl; //方式2,3:外部建立指標物件傳入 //D 是自定義釋放函式或型別 std::shared_ptr<A> ar(a,D()); //方法4,使用lambda作為自定義Free,就這點就比unique_ptr方便 auto my_free = [](void* data){ std::cout << "hello" << std
::endl; free(data);}; char* buf = (char*)malloc(64); std::shared_ptr<char> p1(buf,my_free);//可以不用區域性變數,直接上lambda //方式5: 複製了指標,增加引用計數 std::shared_ptr<Base> lp = p;

例子0 封裝到vector裡

std::vector<std::shared_ptr<A>> TestSharedPtr()
{
    std::vector<std::shared_ptr<A>> args;
    for(int i = 0; i< 400; ++i)
    {
        std::stringstream ss;
        ss << "hello: " << i;
        std::string str = ss.str();
        args.push_back(std::shared_ptr<A>(new A(str)));
    }
    return args;
}

int _tmain(int argc, _TCHAR* argv[])
{
    auto result = TestSharedPtr();
    std::vector<std::shared_ptr<A>> args(result.begin(),result.end());

    for(int i = 0; i< result.size(); ++i)
    {
        auto& one = result[i];
        std::cout << one.use_count() << ":" << one.get()->str_ << std::endl;
    }
    result.clear();
    args.clear();

    return 0;
}

例子1 自定義釋放函式.

struct A
{
    int i;
};

struct D
{
    void operator()(void* data)
    {
        std::cout << "free: " << (int*)data << std::endl;
        free(data);
    }
};

// 使用shared_ptr來呼叫特殊的釋放函式.
void TestCPointer()
{
    A* a = (A*)malloc(sizeof(A));
  a->i = 10;
  std::cout << (int*)a << std::endl;
    std::shared_ptr<A> ar(a,D());
    // 也可以這樣
    //std::shared_ptr<A> ar(a,free);
    std::cout << ar.get()->i << std::endl;
}

例子2 多執行緒訪問

#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
#include <stdlib.h>
#include <Windows.h>

struct Base
{
    Base() { std::cout << "  Base::Base()\n"; }
    // Note: non-virtual destructor is OK here
    ~Base() { std::cout << "  Base::~Base()\n"; }
};

struct Derived: public Base
{
    Derived() { std::cout << "  Derived::Derived()\n"; }
    ~Derived() { std::cout << "  Derived::~Derived()\n"; }
};

void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::shared_ptr<Base> lp = p; // thread-safe, even though the
                                  // shared use_count is incremented
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << "local pointer in a thread:\n"
                  << "  lp.get() = " << lp.get()
                  << ", lp.use_count() = " << lp.use_count() << '\n';
    }
}

struct A
{
    int i;
};


void Free(void* data)
{
    std::cout << "free: " << (int*)data << std::endl;
    free(data);
}

struct D
{
    void operator()(void* data)
    {
        std::cout << "free: " << (int*)data << std::endl;
        free(data);
    }
};

// 使用shared_ptr來呼叫特殊的釋放函式.
void TestCPointer()
{
    A* a = (A*)malloc(sizeof(A));
    a->i = 10;
    std::cout << (int*)a << std::endl;
    // 自定義釋放函式.
    std::shared_ptr<A> ar(a,D());
    // 也可以這樣
    //std::shared_ptr<A> ar(a,free);
    std::cout << ar.get()->i << std::endl;
}

int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();


    std::cout << "Created a shared Derived (as a pointer to Base)\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    std::thread t1(thr, p), t2(thr, p), t3(thr, p);
    std::cout << "Shared ownership between 3 threads and released\n"
              << "ownership from main:\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    t1.detach();
    t2.detach();
    t3.detach();

    while(1)
    {
        if (p.use_count() == 1)
        {
            break;
        }
        Sleep(500);
    }
    std::cout << "All threads completed, the last one deleted Derived\n";
    //TestCPointer();
    return 0;
}

輸出:

Base::Base()
Derived::Derived()
Created a shared Derived (as a pointer to Base)
p.get() = 0x323f8, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:
p.get() = 0x323f8, p.use_count() = 4
local pointer in a thread:
lp.get() = 0x323f8, lp.use_count() = 5
local pointer in a thread:
lp.get() = 0x323f8, lp.use_count() = 5
local pointer in a thread:
lp.get() = 0x323f8, lp.use_count() = 3
All threads completed, the last one deleted Derived
Derived::~Derived()
Base::~Base()