隨着c + + 11在那裏,我問自己是否有一個替代boost :: ptr_containers在c + + 11。我知道我可以使用例如一個std::vector<std::unique_ptr<T> >
,但我不確定這是否是一個完整的替代品。處理這些案件的推薦方式是什麼?stl容器與std :: unique_ptr的vs boost :: ptr_container
回答
他們真的解決了兩個相似但不同的問題。
指針容器是一種將對象存儲在容器中的方式,它恰好是分配內存而不是值的指針。他們盡其所能,以hide事實上,他們是一個指針的容器。這意味着:
- 容器中的條目不能爲NULL。
- 從迭代器和函數獲得的值是引用的類型,而不是指向類型的指針。
- 使用許多標準算法可能會很棘手。而「棘手」,我的意思是破碎。指針容器有自己的內置算法。
然而,事實證明指針容器知道他們是指針的容器,它們可以提供一些新的功能:
- 執行深拷貝,通過使用
clone
成員函數在對象的類型上具有某種「可克隆」概念。 - 容器釋放對象所有權的能力(例如,在淺拷貝之後)。
- 將所有權轉移給其他容器的內置函數。
他們真的是完全不同的概念。有很多東西你必須手動做,指針容器可以自動執行特定的功能。
如果你真的需要一個容器指針,那麼你可以使用容器unique_ptr
。但是,如果你需要存儲一堆你碰巧分配的對象,並且你想要與它們一起玩特定的遊戲,包括所有權等,那麼指針容器並不是一個壞主意。
我想你可以說他們中的一個明確地是指針的容器,而另一個是用於多態對象的容器...... – Mehrdad 2015-04-25 20:17:19
我決定編寫一個簡短的程序,將幾個多態對象放入一個容器(通過指向堆的指針),然後將該容器與std ::算法一起使用。我僅選擇std::remove_if
作爲示例。
這裏是我如何與vector<unique_ptr<T>>
做到這一點:
#include <vector>
#include <memory>
#include <iostream>
class Animal
{
public:
Animal() = default;
Animal(const Animal&) = delete;
Animal& operator=(const Animal&) = delete;
virtual ~Animal() = default;
virtual void speak() const = 0;
};
class Cat
: public Animal
{
public:
virtual void speak() const {std::cout << "Meow\n";}
virtual ~Cat() {std::cout << "destruct Cat\n";}
};
class Dog
: public Animal
{
public:
virtual void speak() const {std::cout << "Bark\n";}
virtual ~Dog() {std::cout << "destruct Dog\n";}
};
class Sheep
: public Animal
{
public:
virtual void speak() const {std::cout << "Baa\n";}
virtual ~Sheep() {std::cout << "destruct Sheep\n";}
};
int main()
{
typedef std::unique_ptr<Animal> Ptr;
std::vector<Ptr> v;
v.push_back(Ptr(new Cat));
v.push_back(Ptr(new Sheep));
v.push_back(Ptr(new Dog));
v.push_back(Ptr(new Sheep));
v.push_back(Ptr(new Cat));
v.push_back(Ptr(new Dog));
for (auto const& p : v)
p->speak();
std::cout << "Remove all sheep\n";
v.erase(
std::remove_if(v.begin(), v.end(),
[](Ptr& p)
{return dynamic_cast<Sheep*>(p.get());}),
v.end());
for (auto const& p : v)
p->speak();
}
此輸出:
Meow
Baa
Bark
Baa
Meow
Bark
Remove all sheep
destruct Sheep
destruct Sheep
Meow
Bark
Meow
Bark
destruct Dog
destruct Cat
destruct Dog
destruct Cat
這對我來說很好。但是我發現翻譯這ptr_vector
問題:
boost::ptr_vector<Animal> v;
v.push_back(new Cat);
v.push_back(new Sheep);
v.push_back(new Dog);
v.push_back(new Sheep);
v.push_back(new Cat);
v.push_back(new Dog);
for (auto const& p : v)
p.speak();
std::cout << "Remove all sheep\n";
v.erase(
std::remove_if(v.begin(), v.end(),
[](Animal& p)
{return dynamic_cast<Sheep*>(&p);}),
v.end());
for (auto const& p : v)
p.speak();
algorithm:1897:26: error: overload resolution selected deleted operator '='
*__first = _VSTD::move(*__i);
~~~~~~~~^~~~~~~~~~~~~~~~~~
test.cpp:75:9: note: in instantiation of function template specialization 'std::__1::remove_if<boost::void_ptr_iterator<std::__1::__wrap_iter<void
**>, Animal>, Sheep *(^)(Animal &)>' requested here
std::remove_if(v.begin(), v.end(),
^
test.cpp:12:13: note: candidate function has been explicitly deleted
Animal& operator=(const Animal&) = delete;
^
1 error generated.
的問題是boost::ptr_vector
一個特點:迭代器不返回內部存儲的指針。他們返回解除引用的指針。因此,當容器與std::algorithms
一起使用時,算法嘗試將存儲的對象而不是存儲的指針複製到對象。
如果一個不小心忘了讓你的多態對象不可複製,再複製語義自動供應,導致運行時錯誤而不是編譯時錯誤:
class Animal
{
public:
Animal() = default;
virtual ~Animal() = default;
virtual void speak() const = 0;
};
現在造成這個錯誤輸出:
Meow
Baa
Bark
Baa
Meow
Bark
Remove all sheep
destruct Cat
destruct Dog
Meow
Baa
Bark
Baa
destruct Cat
destruct Sheep
destruct Dog
destruct Sheep
使用vector<unique_ptr>
時不會發生此運行時錯誤。
存儲指針容器但顯示引用容器的阻抗不匹配與通用算法安全使用容器不一致。實際上,這就是爲什麼ptr_containers帶有許多算法的定製版本。做好這項工作與ptr_containers正確的方法是使用只那些成員算法:
v.erase_if([](Animal& p)
{return dynamic_cast<Sheep*>(&p);});
如果您不需要提供作爲ptr_containers成員的突變序列算法,不要試圖去夠那些在<algorithm>
中,或其他第三方提供的通用算法。
總之,當唯一的其他實用選項是std::vector<boost::shared_ptr<T>>
時,boost :: ptr_containers滿足了真正的需求。但現在std::vector<std::unique_ptr<T>>
,開銷參數消失了。 C++ 11解決方案似乎具有安全性和靈活性兩方面的優勢。如果您需要「克隆語義」,我會認真考慮編寫您自己的clone_ptr<T>
,並將其用於std容器和算法。
重複使用std :: lib會使容器的選項比boost lib更加開放(例如unordered_set/map,forward_list),並且它會使std :: algorithms的選項保持儘可能寬。這就是說,如果你有工作,調試過的代碼已經使用boost :: ptr_containers,那麼沒有迫切需要改變它。
「開銷參數不見了」 - 今天,我用VS2013-Express做了一些測試令人驚訝的是,我通過'ptr_vector'獲得了更好的性能結果,而不是'vector
有趣,感謝報告。我沒有VS2013進行試驗。是'sizeof(unique_ptr
是的,sizeof(uq_ptr)== sizeof(T *)== 4./O2是VS中「最大化速度」。在索引'[]'訪問時,我看到ptr_vector有50%的速度增益。 – 2014-01-16 19:05:11
- 1. boost :: thread和std :: unique_ptr
- 2. boost :: ptr_container和std :: vector <shared_ptr>
- 3. 嵌套unique_ptr和stl容器
- 4. std :: unique_ptr :: release()vs std :: move()
- 5. 在std :: map中插入boost :: unique_ptr
- 6. boost :: ptr_vector vs. std :: vector <std :: unique_ptr <T>>?
- 7. std ::將一個std :: unique_ptr移動到stl容器中。 (MSVC編譯器問題)
- 8. STL容器VS的Structs
- 9. boost :: variant;的std ::的unique_ptr和複製
- 10. 指向std :: unique_ptr的內容
- 11. 在標準容器中使用std :: unique_ptr
- 12. 你可以在`std :: unique_ptr`的容器上使用`std :: remove_if`嗎?
- 13. Boost如何序列化STL容器?
- 14. 二元樹與std :: unique_ptr
- 15. std :: unique_ptr與數組指針
- 16. 的unique_ptr VS auto_ptr的
- 17. Unique_ptr容器或unique_ptr元素
- 18. unique_ptr trouble? (VS 2015)
- 19. 將包含unique_ptr的結構項添加到stl容器中
- 20. Rcpp錯誤:'unique_ptr'不是'std'的成員
- 21. 應該std :: bind與boost :: asio兼容嗎?
- 22. std :: shared_ptr與std容器
- 23. QSharedPointer VS std :: tr1 :: shared_ptr VS boost :: tr1 :: shared_ptr
- 24. std :: unique_ptr ostream插入器
- 25. 如何處理不斷髮展的C++ std :: namespace?例如:std :: tr1 :: shared_ptr vs. std :: shared_ptr vs. boost :: shared_ptr vs. boost :: tr1 :: shared_ptr
- 26. boost :: interprocess - std :: string與std :: vector
- 27. 使用特徵類型與STL容器和std :: vector
- 28. boost unique_ptr Deletor
- 29. 多線程與STL容器
- 30. 克隆分配器和boost中的多態性:: ptr_container
對於'unique_ptr',你仍然需要對這些節點進行解引用,但除此之外它們應該幾乎表現相同。 – 2012-02-27 18:12:18