Với C++ 11 ra khỏi đó, tôi đã tự hỏi bản thân mình nếu có một sự thay thế của boost :: ptr_containers trong C++ 11. Tôi biết tôi có thể sử dụng ví dụ a std::vector<std::unique_ptr<T> >
, nhưng tôi không chắc liệu đây có phải là sự thay thế hoàn toàn không. Cách đề nghị xử lý những trường hợp này là gì?stl container với std :: unique_ptr's vs boost :: ptr_container
Trả lời
Chúng thực sự giải quyết hai vấn đề tương tự nhưng khác nhau.
Vùng chứa con trỏ là một cách để lưu trữ các đối tượng trong vùng chứa mà chỉ xảy ra như là con trỏ tới bộ nhớ được cấp phát thay vì giá trị. Họ làm tất cả mọi thứ trong quyền lực của họ để ẩn thực tế là chúng là một vùng chứa con trỏ. Điều này có nghĩa là:
- Mục nhập trong vùng chứa không thể là NULL.
- Giá trị bạn nhận được từ các trình lặp và chức năng là tài liệu tham khảo đối với loại, không trỏ đến loại.
- Làm việc với nhiều thuật toán chuẩn có thể ... phức tạp. Và bởi "khéo léo", tôi có nghĩa là bị hỏng. Thùng chứa con trỏ có các thuật toán tích hợp của riêng chúng.
Tuy nhiên, thực tế là các thùng chứa con trỏ biết rằng họ đang container của con trỏ, họ có thể cung cấp một số chức năng mới:
- Một chức năng
clone
thành viên đó thực hiện một bản sao sâu, thông qua việc sử dụng của một khái niệm "Cloneable" nhất định về loại đối tượng. - Khả năng của thùng chứa để giải phóng quyền sở hữu đối tượng của nó (ví dụ như bản sao nông).
- Chức năng tích hợp để chuyển quyền sở hữu cho các vùng chứa khác.
Chúng thực sự là các khái niệm khá khác nhau. Có rất nhiều thứ bạn sẽ phải làm bằng tay mà container con trỏ có thể làm tự động với các chức năng chuyên biệt.
Nếu bạn thực sự cần một hộp chứa con trỏ, thì bạn có thể sử dụng vùng chứa unique_ptr
. Nhưng nếu bạn cần lưu trữ một loạt các đối tượng mà bạn tình cờ phân bổ, và bạn muốn chơi các trò chơi đặc biệt với chúng liên quan đến quyền sở hữu và như vậy, thì các thùng chứa con trỏ không phải là một ý tưởng tồi.
Tôi đoán bạn có thể nói rằng một trong số đó rõ ràng là một container con trỏ trong khi cái kia là một container dành cho các đối tượng đa hình ... – Mehrdad
Tôi quyết định viết một chương trình ngắn đưa một vài đối tượng đa hình vào một vùng chứa (bằng con trỏ tới đống), và sau đó sử dụng vùng chứa đó bằng thuật toán std ::. Tôi đã chọn std::remove_if
như một ví dụ.
Sau đây là cách tôi sẽ làm điều đó với 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();
}
đầu ra này:
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
mà có vẻ tốt với tôi. Tuy nhiên tôi thấy dịch này để ptr_vector
có vấn đề:
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.
Vấn đề là một tính năng của boost::ptr_vector
: các vòng lặp không trả lại con trỏ lưu trữ nội bộ. Họ trả lại con trỏ dereferenced.Và do đó khi các container được sử dụng với std::algorithms
, các thuật toán cố gắng sao chép các đối tượng được lưu trữ thay vì các con trỏ được lưu trữ cho các đối tượng.
Nếu một trong vô tình quên để làm cho đối tượng đa hình của bạn không copyable, sau đó copy ngữ nghĩa sẽ được tự động cung cấp, dẫn đến một lỗi thời gian chạy thay vì một lỗi thời gian biên dịch:
class Animal
{
public:
Animal() = default;
virtual ~Animal() = default;
virtual void speak() const = 0;
};
Mà bây giờ dẫn đến sai lầm này đầu ra:
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
Lỗi thời gian chạy này không thể xảy ra khi sử dụng vector<unique_ptr>
.
Sự không phù hợp trở kháng của việc lưu trữ các thùng chứa con trỏ nhưng trình bày các thùng chứa tham chiếu xuất hiện theo tỷ lệ cược với việc sử dụng an toàn các thùng chứa với các thuật toán chung. Thật vậy, đây là lý do tại sao các ptr_containers đi kèm với các phiên bản tùy chỉnh của nhiều thuật toán. Các cách chính xác để làm công việc này với ptr_containers là sử dụng chỉ những thuật toán viên:
v.erase_if([](Animal& p)
{return dynamic_cast<Sheep*>(&p);});
Nếu bạn cần một thuật toán chuỗi đột biến không được cung cấp như một thành viên của ptr_containers, không bị cám dỗ để đạt cho những trong <algorithm>
hoặc các thuật toán chung được cung cấp bởi các bên thứ ba khác.
Tóm lại, tăng :: ptr_containers chứa đầy nhu cầu thực sự khi tùy chọn thực tế duy nhất khác là std::vector<boost::shared_ptr<T>>
. Tuy nhiên bây giờ với std::vector<std::unique_ptr<T>>
, đối số trên không biến mất. Và dường như có cả lợi thế về tính an toàn và linh hoạt với giải pháp C++ 11. Nếu bạn cần "clone ngữ nghĩa", tôi sẽ nghiêm túc xem xét viết clone_ptr<T>
của riêng bạn và sử dụng với các container std và các thuật toán.
Sử dụng lại std :: lib sẽ giữ cho các tùy chọn của bạn chứa mở hơn lib tăng cường (ví dụ: unordered_set/map, forward_list) và sẽ giữ tùy chọn std :: algorithm mở rộng nhất có thể.
Điều đó đang được nói, nếu bạn đã làm việc, mã đã gỡ lỗi đã sử dụng boost :: ptr_containers, không có nhu cầu cấp bách để thay đổi nó.
"đối số trên không còn" - Hôm nay, tôi đã làm một vài thử nghiệm với VS2013-Express và đáng ngạc nhiên là tôi nhận được kết quả hoạt động tốt hơn với 'ptr_vector' so với' vector
Thú vị, cảm ơn báo cáo. Tôi không có VS2013 để thử nghiệm. Là 'sizeof (unique_ptr
Vâng, sizeof (uq_ptr) == sizeof (T *) == 4./O2 là "tối đa hóa tốc độ" trong VS. Tôi thấy tốc độ tăng 50% với ptr_vector trên chỉ mục '[]' truy cập. –
- 1. C++ 0x std :: shared_ptr vs. boost :: shared_ptr
- 2. Khởi container của unique_ptrs ra khỏi danh sách khởi tạo không thành công với GCC 4.7
- 3. Boilerplate typedefs cho container tương thích STL
- 4. Boost Python: container đa hình?
- 5. C++ STL container
- 6. STL container trên stack và heap
- 7. iterating đóng gói container STL lồng nhau
- 8. Làm thế nào để xử lý phát triển C++ std :: namespace? ví dụ: std :: tr1 :: shared_ptr so với std :: shared_ptr so với boost :: shared_ptr vs. boost :: tr1 :: shared_ptr
- 9. Qt có hoạt động tốt với STL & Boost không?
- 10. jsp container vs servlet container
- 11. Tôi nên sử dụng container STL nào cho FIFO?
- 12. STL container yếu tố hủy đơn đặt hàng
- 13. Container STL nào là tốt nhất cho std :: sort? (Liệu nó có quan trọng không?)
- 14. Container STL nào để sử dụng?
- 15. boost :: tokenizer vs boost :: split
- 16. 'size_t' vs 'container :: size_type'
- 17. So sánh điểm nổi trong STL, BOOST
- 18. ACE vs Boost vs Poco vs wxWidgets
- 19. boost :: lock_guard vs boost :: mutex :: scoped_lock
- 20. C++ Là một std :: string a container?
- 21. PThread vs boost :: thread?
- 22. Chọn một container STL với tính độc đáo và đó giữ chèn lệnh
- 23. Intel TBB vs Boost
- 24. C++/STL: std :: chuyển đổi với bước tiến nhất định?
- 25. ném mới std :: ngoại lệ vs ném std :: ngoại lệ
- 26. boost :: asio :: deadline_timer với std :: giá trị thời gian chrono
- 27. boost :: filter_iterator - làm thế nào tôi sẽ làm điều đó với STL?
- 28. ưu điểm của std :: set vs vectơ hoặc bản đồ
- 29. boost :: regex vs std :: regex - không thể tìm thấy phương thức empty()?
- 30. Sử dụng Boost Python & std :: shared_ptr
Với 'unique_ptr', bạn vẫn phải dereference các nút, nhưng khác hơn là họ nên hành xử khá giống nhau. –