簡體   English   中英

C ++共享指針引用數組中的對象

[英]C++ shared pointers referencing an object within an array

才剛剛開始研究智能指針,以及如何使用它們來提高代碼內的效率,我很好奇shared_ptr如何與數組/向量/容器中的類對象反應。

從我讀過的共享指針的一般要點來看,一旦所有指向一個對象的指針都被破壞或重新分配,該對象也將被破壞。 但是,如果我們的對象也存儲在數組/向量中,即使共享對象仍然可以訪問,共享指針是否仍會嘗試銷毀該對象。

有沒有什么辦法可以在設置數組時設置共享指針,這樣可以確保僅在清除數組/向量后才刪除對象,還是必須在數組中使用shared_ptr?

不建議將裸引用與shared_ptr混合使用。 主要原因是因為它違反了引用計數的概念,shared_ptr用來確定何時可以安全地解除分配引用的對象。 任何裸引用的生存期必須比壽命最長的shared_ptr的生存期短,否則崩潰就會醞釀。

如果您想在某種容器中包含一組對象,並且仍然能夠使用shared_ptr訪問這些對象,則最好使用shared_ptr的數組/向量/容器,因為這會使容器“折疊” ”可以說是shared_ptr概念。 這樣做的好處是,當從容器中刪除對象時,將不會立即釋放該對象,反之亦然,引用該對象的共享指針也是如此。

使用shared_ptrs容器的缺點是,由於實際上使用的是指向指針的指針,因此指針數學變得稍微困難​​些。

您應該僅以兩種方式使用共享指針:

1)創建新對象時,

std::shared_ptr<something> ptr(new something);

2)當您將共享指針復制到另一個指針時。

std::shared_ptr<something> copy(ptr);

因此,如果您在數組中創建對象,則它不適合共享指針方案。

如果要在向量中保存使用共享指針分配的對象,則必須保存其共享指針:

std::vector<std::shared_ptr<something> > my_vector;

my_vector.push_back(new something);

清除向量時,所有指針都將清除,因此僅由向量引用的對象將被刪除:

my_vector.clear();  // do "delete something" as required

附帶說明一下,您在問題中說“更有效” ...共享指針並不是更有效,並且它們在軟件中創建的代碼的可能性也不會比您想象的要多。

C ++中非常重要的一點是例外。 保存在智能指針中的對象(在這種情況下,unique_ptr也起作用)將在異常時自動刪除。 這個非常重要。 例如:

std::shared_ptr<something> ptr(new something);

...
if(this_is_true) throw std::logic_error("something's wrong");
...

在上面的代碼中,指針ptr在拋出ptr之前自動被刪除。 這不是我所說的更有效,但是在清潔度方面要好得多。 如果您調用一個可以拋出的函數(例如,另一個new函數),則處理每個調用將變得非常乏味(即,您需要在每次調用中都進行一次try / catch,並且catch必須刪除指針並然后重新拋出。)

因此從某種意義上講,它是有效的。 但是,就執行速度而言,它可能比不使用共享指針快(或慢)。

指向子對象(數組元素或對象成員)的指針可能與指向整個對象的指針共享所有權。 使用模板構造函數為子對象創建shared_ptr

template< class Y > 
shared_ptr( const shared_ptr<Y>& r, T *ptr );

它接受任何類型的shared_ptr ,以及指向目標類型的指針(可能完全不相關)。 構造的shared_ptr與源對象r共享所有權,但是在取消引用時指向ptr

例如,創建一個指向std::array的第三個array元素的指針:

class foo {};
auto array = std::make_shared<std::array<foo, 16>>();
auto element_ptr = std::shared_ptr<foo>(array, array->data() + 2);

或對象的數據成員:

struct foo {
  int i;
};
auto some_foo = std::make_shared<foo>();
auto foo_member = std::shared_ptr<int>(some_foo, &some_foo->i);

可惜沒有像std::make_shared這樣方便的類型推斷“ make”功能,明確指定子對象的類型很煩人。 也許我們應該自己寫:

template <typename Object, typename SubObject>
inline std::shared_ptr<SubObject>
make_sub_ptr(const std::shared_ptr<Object>& c, SubObject* ptr) {
    return {c, ptr};
}

因此我們可以將早期的創建簡化為:

auto element_ptr = make_sub_ptr(array, array->data() + 2);
// ...
auto foo_member = make_sub_ptr(some_foo, &some_foo->i);

Coliru現場演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM