Ответ 1
Fwiw, я думаю, что дизайн можно упростить, если предположить, что контейнер С++ 11 соответствует:
template <class T>
class no_init_allocator
{
public:
typedef T value_type;
no_init_allocator() noexcept {}
template <class U>
no_init_allocator(const no_init_allocator<U>&) noexcept {}
T* allocate(std::size_t n)
{return static_cast<T*>(::operator new(n * sizeof(T)));}
void deallocate(T* p, std::size_t) noexcept
{::operator delete(static_cast<void*>(p));}
template <class U>
void construct(U*) noexcept
{
static_assert(std::is_trivially_default_constructible<U>::value,
"This allocator can only be used with trivally default constructible types");
}
template <class U, class A0, class... Args>
void construct(U* up, A0&& a0, Args&&... args) noexcept
{
::new(up) U(std::forward<A0>(a0), std::forward<Args>(args)...);
}
};
-
Я вижу мало преимуществ для получения от другого распределителя.
-
Теперь вы можете оставить
allocator_traits
дескрипторrebind
. -
Шаблон элементов
construct
наU
. Это помогает, если вы хотите использовать этот распределитель с некоторым контейнером, которому нужно выделить что-то другое, кромеT
(например,std::list
). -
Переместите тест
static_assert
в один элементconstruct
, где это важно.
Вы все равно можете создать using
:
template <class T>
using uninitialised_vector = std::vector<T, no_init_allocator<T>>;
И это все еще не скомпилируется:
unitialised_vector< std::vector<int> > x(10);
test.cpp:447:17: error: static_assert failed "This allocator can only be used with trivally default constructible types"
static_assert(std::is_trivially_default_constructible<U>::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Я думаю, что тест для is_trivially_destructible
является излишним, если вы также не оптимизируете destroy
, чтобы ничего не делать. Но я не вижу никакой мотивации в этом, так как считаю, что в любом случае он должен быть оптимизирован. Без такого ограничения вы можете:
class A
{
int data_;
public:
A() = default;
A(int d) : data_(d) {}
};
int main()
{
uninitialised_vector<A> v(10);
}
И это просто работает. Но если вы сделаете ~A()
нетривиальным:
~A() {std::cout << "~A(" << data_ << ")\n";}
Тогда, по крайней мере, в моей системе вы получите ошибку при построении:
test.cpp:447:17: error: static_assert failed "This allocator can only be used with trivally default constructible types"
static_assert(std::is_trivially_default_constructible<U>::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
т.е. A
уже не является тривиально конструктивным, если он имеет нетривиальный деструктор.
Однако даже с нетривиальным деструктором вы все равно можете:
uninitialised_vector<A> v;
v.push_back(A());
Это работает только, потому что я не справлялся с требованием тривиального деструктора. И при выполнении этого я получаю ~A()
для запуска, как ожидалось:
~A(0)
~A(0)