polymorphic_allocator: khi nào và tại sao tôi nên sử dụng nó?


121

Đây là tài liệu về cppreference , đây là bản nháp đang hoạt động.

Tôi phải thừa nhận rằng tôi không hiểu mục đích thực sự của nó là gì polymorphic_allocatorvà khi nào / tại sao / cách tôi nên sử dụng nó.
Ví dụ, pmr::vectorcó chữ ký sau:

namespace pmr {
    template <class T>
    using vector = std::vector<T, polymorphic_allocator<T>>;
}

Những gì polymorphic_allocatorcung cấp? Gì std::pmr::vectorphục vụ cũng như trong lĩnh vực của cái cũ lỗi thời std::vector? Tôi có thể làm gì bây giờ mà tôi vẫn chưa thể làm được?
Mục đích thực sự của bộ phân bổ đó là gì và khi nào tôi nên sử dụng nó thực sự?


1
Họ cố gắng khắc phục một số vấn đề allocator<T>vốn có. Vì vậy, bạn sẽ thấy giá trị trong đó nếu bạn sử dụng trình phân bổ thường xuyên.
edmz

2
Giấy có liên quan .
edmz

Câu trả lời:


102

Trích dẫn lựa chọn từ cppreference:

Tính đa hình thời gian chạy này cho phép các đối tượng sử dụng polymorphic_allocator hoạt động như thể chúng sử dụng các loại bộ cấp phát khác nhau tại thời điểm chạy mặc dù cùng loại bộ cấp phát tĩnh

Vấn đề với trình phân bổ "thông thường" là họ thay đổi loại vùng chứa. Nếu bạn muốn vectorcó một trình phân bổ cụ thể, bạn có thể sử dụng Allocatortham số mẫu:

auto my_vector = std::vector<int,my_allocator>();

Vấn đề bây giờ là vectơ này không cùng loại với vectơ có bộ cấp phát khác. Ví dụ: bạn không thể chuyển nó vào một hàm yêu cầu vectơ cấp phát mặc định hoặc gán hai vectơ có kiểu cấp phát khác nhau cho cùng một biến / con trỏ, ví dụ:

auto my_vector = std::vector<int,my_allocator>();
auto my_vector2 = std::vector<int,other_allocator>();
auto vec = my_vector; // ok
vec = my_vector2; // error

Bộ cấp phát đa hình là một loại bộ cấp phát đơn với một thành viên có thể xác định hành vi của bộ cấp phát thông qua điều phối động thay vì thông qua cơ chế mẫu. Điều này cho phép bạn có các vùng chứa sử dụng phân bổ cụ thể, tùy chỉnh, nhưng vẫn thuộc loại phổ biến.

Việc tùy chỉnh hành vi của trình cấp phát được thực hiện bằng cách cung cấp cho trình cấp phát một std::memory_resource *:

// define allocation behaviour via a custom "memory_resource"
class my_memory_resource : public std::pmr::memory_resource { ... };
my_memory_resource mem_res;
auto my_vector = std::pmr::vector<int>(0, &mem_res);

// define a second memory resource
class other_memory_resource : public std::pmr::memory_resource { ... };
other_memory_resource mem_res_other;
auto my_other_vector = std::pmr::vector<int>(0, &mes_res_other);

auto vec = my_vector; // type is std::pmr::vector<int>
vec = my_other_vector; // this is ok -
      // my_vector and my_other_vector have same type

Vấn đề chính còn lại, như tôi thấy, là một vùng std::pmr::chứa vẫn không tương thích với vùng std::chứa tương đương bằng cách sử dụng trình cấp phát mặc định. Bạn cần phải đưa ra một số quyết định tại thời điểm thiết kế giao diện hoạt động với vùng chứa:

  • có khả năng vùng chứa được chuyển vào có thể yêu cầu phân bổ tùy chỉnh không?
  • nếu vậy, tôi có nên thêm một tham số mẫu (để cho phép các trình cấp phát tùy ý) hay tôi nên bắt buộc sử dụng một trình cấp phát đa hình?

Giải pháp khuôn mẫu cho phép bất kỳ trình cấp phát nào , bao gồm cả trình cấp phát đa hình, nhưng có những nhược điểm khác (kích thước mã được tạo, thời gian biên dịch, mã phải được hiển thị trong tệp tiêu đề, tiềm ẩn nguy cơ "nhiễm loại" tiếp tục đẩy vấn đề ra bên ngoài). Mặt khác, giải pháp cấp phát đa hình ra lệnh rằng phải sử dụng trình cấp phát đa hình . Điều này loại trừ việc sử dụng std::các vùng chứa sử dụng trình cấp phát mặc định và có thể có ý nghĩa đối với việc giao tiếp với mã kế thừa.

So với trình cấp phát thông thường, trình cấp phát đa hình có một số chi phí nhỏ, chẳng hạn như chi phí lưu trữ của con trỏ memory_resource (rất có thể là không đáng kể) và chi phí điều phối hàm ảo để cấp phát. Vấn đề chính, thực sự, có lẽ là thiếu khả năng tương thích với mã kế thừa không sử dụng bộ cấp phát đa hình.


2
Vì vậy, bố trí nhị phân cho std::pmr::các lớp rất có thể khác nhau?
Euri Pinhollow

12
@EuriPinhollow bạn không thể reinterpret_castgiữa a std::vector<X>std::pmr::vector<X>, nếu đó là những gì bạn đang yêu cầu.
davmac

4
Đối với các trường hợp đơn giản, trong đó tài nguyên bộ nhớ không phụ thuộc vào biến thời gian chạy, một trình biên dịch tốt sẽ phân phối và bạn kết thúc với một trình cấp phát đa hình mà không tốn thêm chi phí (ngoại trừ việc lưu trữ con trỏ thực sự không phải là vấn đề). Tôi nghĩ nó là điều đáng nói.
DeiDei

1
@ Yakk-AdamNevraumont "một vùng std::pmr::chứa vẫn không tương thích với vùng std::chứa tương đương bằng cách sử dụng bộ cấp phát mặc định" . Không có toán tử gán nào được định nghĩa từ cái này sang cái kia. Khi nghi ngờ, hãy thử: godbolt.org/z/Q5BKev (mã không chính xác như trên vì gcc / clang có các lớp phân bổ đa hình trong không gian tên "thử nghiệm").
davmac

1
@davmac Ah, vì vậy không có hàm template<class OtherA, std::enable_if< A can be constructed from OtherA > vector( vector<T, OtherA>&& )tạo. Tôi không chắc chắn và không biết tìm trình biên dịch ở đâu có pmr tuân thủ TS.
Yakk - Adam Nevraumont

33

polymorphic_allocatorlà đối với bộ cấp phát tùy chỉnh cũng như std::functionđối với một cuộc gọi hàm trực tiếp.

Nó chỉ cho phép bạn sử dụng một trình phân bổ với vùng chứa của bạn mà không cần phải quyết định, tại điểm khai báo, cái nào. Vì vậy, nếu bạn gặp trường hợp có nhiều hơn một bộ phân bổ sẽ thích hợp, bạn có thể sử dụng polymorphic_allocator.

Có thể bạn muốn ẩn trình phân bổ nào được sử dụng để đơn giản hóa giao diện của mình hoặc có thể bạn muốn hoán đổi nó cho các trường hợp thời gian chạy khác nhau.

Đầu tiên, bạn cần mã cần một bộ cấp phát, sau đó bạn cần muốn có thể hoán đổi cái nào được sử dụng, trước khi xem xét vector pmr.


7

Một nhược điểm của trình phân bổ đa hình polymorphic_allocator<T>::pointerlà luôn luôn công bằng T*. Điều đó có nghĩa là bạn không thể sử dụng chúng với các con trỏ ưa thích . Nếu bạn muốn làm điều gì đó như đặt các phần tử của a vectortrong bộ nhớ dùng chung và truy cập chúng thông qua boost::interprocess::offset_ptrs , bạn cần sử dụng trình cấp phát không đa hình cũ thông thường cho việc đó.

Vì vậy, mặc dù các trình cấp phát đa hình cho phép bạn thay đổi hành vi phân bổ mà không thay đổi kiểu tĩnh của vùng chứa, nhưng chúng giới hạn phân bổ là gì.


2
Đây là một điểm mấu chốt và là một lỗi lớn. Giấy hướng tới những con trỏ ưa thích có ý nghĩa của Arthur O'Dwyer khám phá lãnh thổ, cũng như cuốn sách "Làm chủ c ++ 17 STL" của ông
xem

bạn có thể đưa ra một trường hợp sử dụng trong thế giới thực của việc sử dụng bộ cấp phát đa hình không?
darune
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.