How to: 建立和使用 shared_ptr 執行個體
shared_ptr 型別是智慧型指標在為情節設計一個以上的擁有者可能必須管理物件存留期在記憶體中的 C++ 標準程式庫中。 在您使用您可以複製其 shared_ptr 後,請將它在函式引數的值,並將它指派給其他 shared_ptr 執行個體。 對相同的所有執行個體的物件及該一「的控制區塊的」共用存取參考計數遞增和遞減,當新的 shared_ptr ,將超出範圍或重設。 在參考計數達到零時,控制區塊刪除記憶體資源和本身。
下圖顯示的是指向記憶體位置的多個 shared_ptr 執行個體。
範例
可能的話,,當記憶體資源第一次建立時,請使用 make_shared (<memory>) 函式建立 shared_ptr 。 make_shared 是例外狀況安全。 它會使用相同的呼叫中配置的控制區塊和資源的記憶體因而降低建構額外負荷。 如果您不使用 make_shared,則您必須使用明確的新運算式建立物件,然後再將它傳遞給 shared_ptr 建構函式。 下列範例顯示各種不同的方式與新物件同時宣告和初始化 shared_ptr 。
// Use make_shared function when possible.
auto sp1 = make_shared<Song>(L"The Beatles", L"Im Happy Just to Dance With You");
// Ok, but slightly less efficient.
// Note: Using new expression as constructor argument
// creates no named variable for other code to access.
shared_ptr<Song> sp2(new Song(L"Lady Gaga", L"Just Dance"));
// When initialization must be separate from declaration, e.g. class members,
// initialize with nullptr to make your programming intent explicit.
shared_ptr<Song> sp5(nullptr);
//Equivalent to: shared_ptr<Song> sp5;
//...
sp5 = make_shared<Song>(L"Elton John", L"I'm Still Standing");
下列範例顯示如何宣告和初始化採用物件共用擁有權另一 shared_ptr已配置的 shared_ptr 執行個體。 假設, sp2 是初始化的 shared_ptr。
//Initialize with copy constructor. Increments ref count.
auto sp3(sp2);
//Initialize via assignment. Increments ref count.
auto sp4 = sp2;
//Initialize with nullptr. sp7 is empty.
shared_ptr<Song> sp7(nullptr);
// Initialize with another shared_ptr. sp1 and sp2
// swap pointers as well as ref counts.
sp1.swap(sp2);
shared_ptr 也適用於 Standard Template Library (STL) 容器,當您使用複製項目的演算法時。 您可以將 shared_ptr中的項目,然後將它複製到有理解的其他容器基礎記憶體有效,只要需要且不再。 下列範例在向量顯示如何在 shared_ptr 執行個體的 replace_copy_if 演算法。
vector<shared_ptr<Song>> v;
v.push_back(make_shared<Song>(L"Bob Dylan", L"The Times They Are A Changing"));
v.push_back(make_shared<Song>(L"Aretha Franklin", L"Bridge Over Troubled Water"));
v.push_back(make_shared<Song>(L"Thal�a", L"Entre El Mar y Una Estrella"));
vector<shared_ptr<Song>> v2;
remove_copy_if(v.begin(), v.end(), back_inserter(v2), [] (shared_ptr<Song> s)
{
return s->artist.compare(L"Bob Dylan") == 0;
});
for_each(v2.begin(), v2.end(), [] (shared_ptr<Song> s)
{
wcout << s->artist << L":" << s->title << endl;
});
您可以使用 dynamic_pointer_cast、 static_pointer_cast和 const_pointer_cast 轉換成 shared_ptr。 這些函式類似 dynamic_cast、 static_cast和 const_cast 運算子。 下列範例顯示如何測試每個項目的衍生型別在基底類別 shared_ptr 的向量,然後複製元素並顯示其相關資訊。
vector<shared_ptr<MediaAsset>> assets;
assets.push_back(shared_ptr<Song>(new Song(L"Himesh Reshammiya", L"Tera Surroor")));
assets.push_back(shared_ptr<Song>(new Song(L"Penaz Masani", L"Tu Dil De De")));
assets.push_back(shared_ptr<Photo>(new Photo(L"2011-04-06", L"Redmond, WA", L"Soccer field at Microsoft.")));
vector<shared_ptr<MediaAsset>> photos;
copy_if(assets.begin(), assets.end(), back_inserter(photos), [] (shared_ptr<MediaAsset> p) -> bool
{
// Use dynamic_pointer_cast to test whether
// element is a shared_ptr<Photo>.
shared_ptr<Photo> temp = dynamic_pointer_cast<Photo>(p);
return temp.get() != nullptr;
});
for_each(photos.begin(), photos.end(), [] (shared_ptr<MediaAsset> p)
{
// We know that the photos vector contains only
// shared_ptr<Photo> objects, so use static_cast.
wcout << "Photo location: " << (static_pointer_cast<Photo>(p))->location_ << endl;
});
您可以透過下列方式將 shared_ptr 傳遞至另一個函式:
將 shared_ptr 值。 這個叫用複製建構函式,並將參考計數,並且讓被呼叫端擁有者。 此作業的少量額外負荷,可能很大視 shared_ptr 物件進行。 請使用這個選項,當程式碼協定 (隱含或明確) 在呼叫端和被呼叫端之間需要被呼叫端是擁有人。
透過 shared_ptr 參考或常數參考。 在這種情況下,參考計數不會增加,因此,被呼叫端可以存取指標,只要呼叫端不超出範圍。 或者,接收者可以決定建立根據參考的 shared_ptr 進而符合共用的擁有者。 請使用這個選項,當呼叫端不了解被呼叫端時,或者,如果您必須透過 shared_ptr 和要基於效能考量時避免複製作業。
將基底指標或參考至基礎物件。 這可讓被呼叫端使用物件,但是,使它共用擁有權或擴充的存留期。 如果被呼叫端會從原始指標的 shared_ptr ,則新 shared_ptr 與原始無關的和不控制基礎資源。 請使用這個選項,當呼叫端和被呼叫端之間合約明確指定時呼叫端保留 shared_ptr 存留期的擁有權。
當您決定如何透過 shared_ptr,判斷被呼叫端是否必須共用基底資源的擁有權。 「Owner」是可以使基礎資源使用的物件或函式,只要需要它。 如果呼叫端必須確保被呼叫端可以擴充指標的存留期在其 (函式) 的存留期之外的,請使用選項。 如果您不在乎則被呼叫端是否擴充存留期,則傳遞由參考和讓被呼叫端複製它。
如果您必須允許 Helper 對基底指標的函式存取,因此,您知道 Helper 函式將使用指標並傳回,則呼叫的函式傳回之前,則函式不需要共用基底指標的擁有權。 它只能存取在呼叫端的 shared_ptr的存留期內的指標。 在這種情況下,傳遞 shared_ptr 參考是安全的,或是原始指標或參考至基礎物件。 以這種方式提供一個小效能優點,也可以協助您以程式設計的原因。
在某些情況下,例如在 std:vector<shared_ptr<T>>,您可能必須透過每個 shared_ptr 到 Lambda 運算式主體或具名函式物件。 如果 lambda 或函式不儲存指標,則傳遞 shared_ptr 參考不會叫用每個元素的複製建構函式。
下列範例顯示 shared_ptr 如何多載各種比較運算子可在 shared_ptr 執行個體所擁有的記憶體的指標比較。
// Initialize two separate raw pointers.
// Note that they contain the same values.
auto song1 = new Song(L"Village People", L"YMCA");
auto song2 = new Song(L"Village People", L"YMCA");
// Create two unrelated shared_ptrs.
shared_ptr<Song> p1(song1);
shared_ptr<Song> p2(song2);
// Unrelated shared_ptrs are never equal.
wcout << "p1 < p2 = " << std::boolalpha << (p1 < p2) << endl;
wcout << "p1 == p2 = " << std::boolalpha <<(p1 == p2) << endl;
// Related shared_ptr instances are always equal.
shared_ptr<Song> p3(p2);
wcout << "p3 == p2 = " << std::boolalpha << (p3 == p2) << endl;