Com as tendências mais recentes sobre aplicativos C e C ++, e com os últimos anos, quero dizer que os std::allocator
s sejam usados com muito mais frequência do que realmente é.
Os aplicativos modernos geralmente são multithread ou com forma de simultaneidade, e gerenciam uma quantidade significativa de memória, especialmente em alguns campos, como jogos e aplicativos multimídia; portanto, o alto custo usual das alocações / desalocações aumenta e afeta os desempenhos ainda mais do que em aplicativos antigos.
Mas, pelo que vejo esse tipo de gerenciamento de memória através de std::allocator
s, não é popular, não posso nem contar uma biblioteca que conheço, que esteja usando qualquer lógica sobre uma maneira padronizada de gerenciar memória.
Existe uma verdadeira razão pela qual std::allocator
não é popular? Razões técnicas?
fonte
std::allocator
é extremamente fácil de usar.std::allocator
que (que é basicamente um invólucronew
e posicionamentonew
) não é tão usado? Ou você está se perguntando por que o conceito C ++ deAllocator
widley não é usado? São duas perguntas diferentes.Respostas:
Existem duas perguntas aqui:
1) Por que não é
std::allocator
mais usado?A resposta curta é porque, para a maioria dos usos, usar
new
edelete
é suficiente.Primeiro, uma breve visão geral do objetivo do C ++ 11 Allocator. Basicamente, quando você faz um
new Foo
, ele aloca memória e depois constrói o objeto nessa memória.Mas e se você precisasse alocar memória e construir como duas etapas separadas. O exemplo clássico disso é
std::vector
, que pode alocar memória sem inicializá-la imediatamente, mas constrói os elementos à medida que você os adiciona ao contêiner. O objetivostd::allocator
é fornecer uma interface para executar essas etapas separadas de maneira uniforme.No entanto, para a maioria dos usuários, eles não precisam desse nível de controle, porque é apenas mais uma coisa a ser lembrada ao limpar suas exceções.
2) Por que mais coisas não usam o conceito de C ++
Allocator
?Principalmente a necessidade não existe. As únicas classes que tendem a usá-las são aquelas que desejam dar a seus usuários mais controle sobre a fonte da memória que eles alocam. Os contêineres da biblioteca Padrão são gravados dessa maneira para que o usuário possa tomar essas decisões, se quiserem, mas eles usam o alocador normal como padrão.
fonte
A popularidade de um conceito de linguagem ou biblioteca está em uma correlação inversa com sua complexidade subjacente.
O
std::allocator
conceito é de baixo nível e, como tal, apresenta possíveis armadilhas. Ter um alocador personalizado adiantado provavelmente será considerado uma otimização prematura. Além disso, de maneira semelhante a outros conceitos de baixo nível, geralmente é preferível delegar o gerenciamento de alocação de trabalho a bibliotecas (stdlib, boost), a menos que a sobrecarga de lidar com a complexidade de suas próprias alocações seja absolutamente justificada.Considere os ponteiros como apenas um exemplo de apoio desta tese. Adoramos ponteiros por seu acesso irrestrito à memória e zero sobrecarga, mas em C ++ sabemos melhor usar wrappers com escopo / raii para gerenciar a complexidade, ou seja, até que precisemos explicitamente do desempenho ou que todos possamos concordar com alguma semântica não-proprietária para certos casos de uso bem definidos.
Ao usar um std :: allocator é preciso considerar a ABI e as compatibilidades API, e pergunta maravilhosa, como o comportamento desejado quando o código está envolvido
std::vector<T,A1>().swap(std::vector<T,A2>())
com diferente (e stateful!)A1
EA2
alocadores. Além disso, alguns contêineres nem usam o alocador da maneira que você pretendia! Dê uma olhadastd::list<T,A>
oustd::map<K,T,C,A>
por exemplo. A expectativa natural é que o alocador seja usado para alocar objetos do tipoT
para uma lista ou apair<const K,T>
para um mapa; no entanto, na prática, uma implementação de biblioteca padrão solicita a alocação de um nó de lista ou mapa, e mesmo o tamanho do nó pode ser diferente entre versões de lançamento e depuração. Alocadores personalizados são repletos de minúcias, e a complexidade e os detalhes adicionados são desnecessários para as tarefas de programação mais comuns.fonte
std::unique_ptr<T>
para possuir memória em vez deT *
?Um alocador é uma política injetada em dependência, nos contêineres padrão. Ele existe principalmente para permitir que o código do cliente separe a política de alocação da instanciação, em contêineres já implementados .
O problema aparece quando você precisa usar std :: containers, e a política de alocação padrão (conforme implementada por std :: alocador) não se adequa às necessidades do seu projeto (por exemplo, você deseja que a implementação std :: vector seja lançada se houver mais 1024 objetos são alocados, você deseja usar um conjunto de memórias ou garantir que todas as alocações sejam pré-alocadas em uma determinada área de memória e assim por diante).
Se você não pudesse injetar um alocador diferente nos contêineres, isso o proibiria de usar o std :: containers todo em alguns projetos.
Para contornar isso (e garantir que você ainda possa usar os std :: containers quando tiver requisitos complexos de memória), o alocador é um parâmetro de modelo para os containers.
Para responder à sua pergunta : a maioria das pessoas não usa std :: alocadores porque, quando escrevem o código do cliente, têm controle total das alocações - portanto, não precisam injetar uma política de alocação - e, quando usam o código da biblioteca, o std :: alocador é geralmente suficiente.
fonte