Các mẫu lớp trong ::std
không gian tên thường có thể được các chương trình dành riêng cho các kiểu do người dùng định nghĩa. Tôi không tìm thấy bất kỳ ngoại lệ cho quy tắc này cho std::allocator
.
Vì vậy, tôi có được phép chuyên môn hóa std::allocator
cho các loại của riêng tôi? Và nếu tôi được phép, tôi có cần cung cấp cho tất cả các thành viên của std::allocator
mẫu chính, với điều kiện là nhiều trong số họ có thể được cung cấp bởi std::allocator_traits
(và do đó không được chấp nhận trong C ++ 17)?
Xem xét chương trình này
#include<vector>
#include<utility>
#include<type_traits>
#include<iostream>
#include<limits>
#include<stdexcept>
struct A { };
namespace std {
template<>
struct allocator<A> {
using value_type = A;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using propagate_on_container_move_assignment = std::true_type;
allocator() = default;
template<class U>
allocator(const allocator<U>&) noexcept {}
value_type* allocate(std::size_t n) {
if(std::numeric_limits<std::size_t>::max()/sizeof(value_type) < n)
throw std::bad_array_new_length{};
std::cout << "Allocating for " << n << "\n";
return static_cast<value_type*>(::operator new(n*sizeof(value_type)));
}
void deallocate(value_type* p, std::size_t) {
::operator delete(p);
}
template<class U, class... Args>
void construct(U* p, Args&&... args) {
std::cout << "Constructing one\n";
::new((void *)p) U(std::forward<Args>(args)...);
};
template<class U>
void destroy( U* p ) {
p->~U();
}
size_type max_size() const noexcept {
return std::numeric_limits<size_type>::max()/sizeof(value_type);
}
};
}
int main() {
std::vector<A> v(2);
for(int i=0; i<6; i++) {
v.emplace_back();
}
std::cout << v.size();
}
Đầu ra của chương trình này với libc ++ (Clang with -std=c++17 -Wall -Wextra -pedantic-errors -O2 -stdlib=libc++
) là:
Allocating for 2
Constructing one
Constructing one
Allocating for 4
Constructing one
Constructing one
Allocating for 8
Constructing one
Constructing one
Constructing one
Constructing one
8
và đầu ra với libstdc ++ (Clang with -std=c++17 -Wall -Wextra -pedantic-errors -O2 -stdlib=libstdc++
) là:
Allocating for 2
Allocating for 4
Constructing one
Constructing one
Allocating for 8
Constructing one
Constructing one
Constructing one
Constructing one
8
Như bạn có thể thấy libstdc ++ không phải lúc nào cũng tôn vinh sự quá tải construct
mà tôi đã cung cấp và nếu tôi loại bỏconstruct
, destroy
hoặc max_size
các thành viên, thì chương trình thậm chí không biên dịch với libstdc ++ phàn nàn về những thành viên bị mất này, mặc dù chúng được cung cấp bởi std::allocator_traits
.
Chương trình có hành vi không xác định và do đó cả hai thư viện chuẩn đều đúng hay hành vi của chương trình được xác định rõ và thư viện chuẩn cần có để sử dụng chuyên môn của tôi?
Lưu ý rằng có một số thành viên từ std::allocator
mẫu chính mà tôi vẫn bỏ quên trong chuyên môn của mình. Tôi có cần thêm chúng không?
Nói chính xác, tôi đã bỏ đi
using is_always_equal = std::true_type
được cung cấp bởi std::allocator_traits
vì bộ cấp phát của tôi trống, nhưng sẽ là một phần của std::allocator
giao diện.
Tôi cũng bỏ qua pointer
, const_pointer
, reference
, const_reference
, rebind
và address
, tất cả đều được cung cấp bởistd::allocator_traits
và bị phản đối trong C ++ 17 std::allocator
's giao diện.
Nếu bạn nghĩ rằng cần phải xác định tất cả những điều này để khớp với std::allocator
giao diện, thì vui lòng xem xét chúng được thêm vào mã.