2016-09-07 2 views
4

Я изучаю/играю с распределителями, пытаясь понять, как это работает. Но у меня возникают проблемы с попыткой реализовать тривиальный контейнер, который принимает распределитель. Сейчас я закончил с этим:тривиальный контейнер, предназначенный для распределителя?

template<class T, class Allocator =std::allocator<T>> class Container { 
public: 
    using allocator_type = Allocator; 
    using value_type  = T; 
    using pointer   = typename std::allocator_traits<allocator_type>::pointer; 
    using reference   = value_type&; 
    using size_type   = std::size_t; 

    Container(size_type n =0 , const allocator_type& allocator =allocator_type()){ 
     std::cout << "ctor" << std::endl; 
     allocator.allocate(n); 
    }; 
}; 

int main(int argc, const char* argv[]){ 
    Container<int> c {5}; 
    return 0; 
} 

Это дает мне ошибку member function 'allocate' not viable: 'this' argument has type 'const allocator_type' (aka 'const std::__1::allocator<int>'), but function is not marked const

Как исправить эту ошибку, пожалуйста? Я что-то упускаю ? Я намерен использовать черты позже, но сначала хотел бы, чтобы он работал, используя старый путь.

+0

It это не функция, но это 'allocator', который помечен' const'. Вы можете посмотреть, как libC++, libstdC++ реализует это в чем-то вроде 'std :: vector'. – NathanOliver

+0

стандартные контейнеры обычно используют эту константную ссылку для инициализации своего собственного члена (или базового класса) и выделения вызова для этого элемента. – SergeyA

ответ

1

Ваша линия

allocator.allocate(n); 

попытки вызвать allocate метод allocator, который не определен в качестве метода const. Однако, если вы посмотрите, тип allocator: const allocator_type&, то есть константа, ссылка на allocator_type.

Как вы можете использовать его тогда? Одна вещь, которую вы обычно можете делать с объектом const (или ссылкой на один), состоит в том, чтобы построить из него другой неконстантный объект. Это, например, строит:

allocator_type(allocator).allocate(n); 

Как Сергей правильно отмечает в комментариях, это довольно часто не построить временную Времнную allocator_type, а сделать такой элемент:

allocator_type m_alloc; // Should probably be private 

    Container(size_type n =0 , const allocator_type& allocator =allocator_type()) : 
      m_alloc{allocator}{ 
     std::cout << "ctor" << std::endl; 
     m_alloc.allocate(n); 
    }; 
+0

Было бы плохой практикой, чтобы const_cast это прочь? Хотя сделать его участником кажется довольно естественным и элегантным. –

+0

@ JiříLechner 'const_cast's, как правило, являются явным признаком некоторой проблемы. Здесь, также, как вы заметили, есть очень естественный способ обойти его, так почему бы и нет? –

+0

Ещё один вопрос. Я хотел бы использовать unique_ptr. Это хорошая идея, сделавшая специализацию распределителя, который вернет уникальный_ptr или окажется вне сферы действия задания распределителя? –

Смежные вопросы