Klassenvorlagen im ::std
Namespace können im Allgemeinen durch Programme für benutzerdefinierte Typen spezialisiert werden. Ich habe keine Ausnahme von dieser Regel für gefunden std::allocator
.
Darf ich mich also auf std::allocator
meine eigenen Typen spezialisieren? Und wenn ich darf, muss ich dann alle Mitglieder der std::allocator
primären Vorlage bereitstellen , da viele von ihnen von bereitgestellt werden können std::allocator_traits
(und daher in C ++ 17 veraltet sind)?
Betrachten Sie dieses Programm
#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();
}
Die Ausgabe dieses Programms mit libc ++ (Clang with -std=c++17 -Wall -Wextra -pedantic-errors -O2 -stdlib=libc++
) ist:
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
und die Ausgabe mit libstdc ++ (Clang with -std=c++17 -Wall -Wextra -pedantic-errors -O2 -stdlib=libstdc++
) ist:
Allocating for 2
Allocating for 4
Constructing one
Constructing one
Allocating for 8
Constructing one
Constructing one
Constructing one
Constructing one
8
Wie Sie sehen können libstdc ++ ehren nicht immer die Überlastung , construct
dass ich zur Verfügung gestellt haben , und wenn ich die entfernen construct
, destroy
oder max_size
Mitglieder, dann wird das Programm nicht einmal mit libstdc ++ beschwerte sich über diese fehlenden Mitglieder kompilieren, obwohl sie geliefert werden std::allocator_traits
.
Hat das Programm ein undefiniertes Verhalten und sind daher beide Standardbibliotheken korrekt, oder ist das Verhalten des Programms genau definiert und die Standardbibliothek für die Verwendung meiner Spezialisierung erforderlich?
Beachten Sie, dass es einige Mitglieder aus std::allocator
der primären Vorlage gibt, die ich in meiner Spezialisierung noch ausgelassen habe. Muss ich sie auch hinzufügen?
Um genau zu sein, habe ich ausgelassen
using is_always_equal = std::true_type
std::allocator_traits
Dies wird von bereitgestellt, da mein Allokator leer ist, aber Teil der std::allocator
Schnittstelle wäre.
Ich verließ auch heraus pointer
, const_pointer
, reference
, const_reference
, rebind
und address
, die alle durch zur Verfügung gestellt werdenstd::allocator_traits
und in C ++ als veraltet 17 für std::allocator
‚s - Schnittstelle.
Wenn Sie der Meinung sind, dass alle diese Elemente so definiert werden müssen, dass sie mit der std::allocator
Benutzeroberfläche übereinstimmen , sollten Sie sie dem Code hinzufügen.