Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

auto_ptr、unique_ptr、shared_ptr

範本auto_ptr是C++98提供的解決方案,C++11已摒棄。

範本unique_ptr、shared_ptr是C++11提供的解決方案.

為什麼要摒棄auto_ptr呢?

先來看下面的賦值語句:

auto_ptr<string> ps(new string("I am a boy."));
auto_ptr<stirng> vocation;
vocation = ps;

上述賦值語句將完成什麼工作呢?如果ps和vocation是常規指針,則兩個指針將指向同一個string對象。這是不能接受的,因為程序將試圖刪除同一個對像兩次--一次是ps過期時,一次是vocation過期時。要避免這種問題,方法有多種。

  • 定義賦值運算子,使之執行深賦值。這樣兩個指針將指向不同的對象,其中的一個對像是另一個對象的副本。
  • 建立所有權(ownership)概念,對於特定的對象,只能有一個智能指針可擁有它,這樣只能擁有對象的智能指針的建構函式會刪除該對象。然後,讓賦值操作轉讓所有權。這就是用於auto_ptr和unique_ptr的策略,但unique_ptr的策略更嚴格。
  • 建立智能更高的指針,跟蹤引用特定對象的智能指針數。這稱為引用計數(reference counting)。例如,賦值時,計數將加1,而指針過期時,計數將減1。僅當最後一個指針過期時,才呼叫delete。這是shared_ptr採用的策略。

每種方法都有其用途,

1 下面是一個不適合使用auto_ptr的示例:

#include <iostream>
#include <string>
#include <memory>

using namespace std;

int main()
{
    auto_ptr<string> films[5] =
    {
        auto_ptr<string> (new string("one")),
        auto_ptr<string> (new string("two")),
        auto_ptr<string> (new string("three")),
        auto_ptr<string> (new string("four")),
        auto_ptr<string> (new string("five"))
    };
    auto_ptr<string> pwin;
    pwin = films[2];  // films[2] lose ownership

    cout << "films data is: " << endl;
    for(auto_ptr<string> s : films)
        cout << *s << endl;
    cout << "pwin: " << *pwin << endl;

    return 0;
}

下面是該程序的輸出:

films data is:
one
two

Process returned -1073741819 (0xC0000005)   execution time : 1.659 s
Press any key to continue.

錯誤的使用auto_ptr可能導致問題(這種程式碼的行為是不確定的,其行為可能隨系統而異)。這裡的問題在於,下面的語句將所有權從films[2]轉讓給pwin:

pwin = films[2];  // films[2] lose ownership

這導致films[2]不再引用該字串。在auto_ptr放棄對象的所有權後,邊可能使用它來訪問該對象。當程序列印films[2]指向的字串時,卻發現這是一個空指針,因此發生錯誤。

2 如果使用shared_ptr替換auto_ptr,則程序將正常運行。

示例程式碼:

#include <iostream>
#include <string>
#include <memory>

using namespace std;

int main()
{
    shared_ptr<string> films[5] =
    {
        shared_ptr<string> (new string("one")),
        shared_ptr<string> (new string("two")),
        shared_ptr<string> (new string("three")),
        shared_ptr<string> (new string("four")),
        shared_ptr<string> (new string("five"))
    };
    shared_ptr<string> pwin;
    pwin = films[2];

    cout << "films data is: " << endl;
    for(shared_ptr<string> s : films)
        cout << *s << endl;
    cout << "pwin: " << *pwin << endl;

    return 0;
}

其輸出如下:

films data is:
one
two
three
four
five
pwin: three

這次pwin和films[2]指向同一個對象,而引用計數從1增加到2。在程序末尾,後聲明的pwin首先呼叫其解構函式,該解構函式將引用計數降低到1。然後,shared_ptr陣列的成員被釋放,對films[2]呼叫解構函式時,將引用計數降低到0,並釋放以前分配的空間。

3 如果使用unique_ptr替換auto_ptr

#include <iostream>
#include <string>
#include <memory>

using namespace std;

int main()
{
    unique_ptr<string> films[5] =
    {
        unique_ptr<string> (new string("one")),
        unique_ptr<string> (new string("two")),
        unique_ptr<string> (new string("three")),
        unique_ptr<string> (new string("four")),
        unique_ptr<string> (new string("five"))
    };
    unique_ptr<string> pwin;
    pwin = films[2];

    cout << "films data is: " << endl;
    for(unique_ptr<string> s : films)
        cout << *s << endl;
    cout << "pwin: " << *pwin << endl;

    return 0;
}

則程序將在下述程式碼行出現編譯錯誤。

pwin = films[2];  // films[2] lose ownership