Última atualização:2026-10-12
C++ evitar o construtor padrão¶
Em C++, alguns contêineres, ao ajustar o tamanho com o método resize(), acabam chamando o construtor padrão, o que pode não ser o comportamento desejado. Este artigo apresenta como usar um alocador personalizado para controlar esse processo e evitar a chamada da construção padrão.
Exemplo 1:
Você sabe o que é impresso neste caso?
A resposta é:
Aqui é preciso entender alguns pontos:
Primeiro: por que os dados, após o resize, viraram 0 — o que aconteceu?
Segundo: se eu quiser manter os dados originais, como fazer? Ou seja, quero que a saída seja:
Terceiro: o que acontece se os membros do vector não tiverem construtor padrão?
Quarto: quais são as limitações do resize?
Pois é exatamente isso que esta seção vai estudar: como fazer o resize evitar a chamada à construção padrão.
Nota: o espaço é limitado; o código completo da versão simplificada desta seção está na comunidade.
1. Análise do resize¶
Para deixar o texto mais fluido, usei o exemplo abaixo: proíbo a construção de Foo e, em seguida, faço resize dele num vector.
Neste haverá erro de compilação, e veremos uma pilha de mensagens de erro.
Primeiro problema: vê-se que a pilha de chamadas chegou a __uninitialized_default_n, que então verifica se o tipo atual é um tipo trivial — eis a primeira limitação do resize!
required from '_ForwardIterator std::__uninitialized_default_n(_ForwardIterator, _Size) [with _ForwardIterator = Foo*; _Size = long unsigned int]'
710 | return __uninitialized_default_n_1<__is_trivial(_ValueType)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
711 | && __can_fill>::
Segundo problema: como proibimos a construção padrão, o alocador falha ao fazer placement new de um objeto padrão no endereço original, e aí vem o erro — eis a segunda limitação!
gcc/14.1.0_1/include/c++/14/bits/stl_construct.h:119:7: error: use of deleted function 'Foo::Foo()'
119 | ::new((void*)__p) _Tp(std::forward<_Args>(__args)...);
| ^~~~~~~~~~~~~~~~~~~
Dito isso, podemos entrar no assunto: vê-se que, no resize, usa-se o alocador para alocar memória; quando o tamanho passado é maior que size (assumindo aqui que está dentro de capacity, ou seja, o endereço é válido), usa-se o alocador para fazer placement new de um objeto construído pelo construtor padrão.
A implementação do código-fonte do gcc pode ser mostrada aqui — simples, não é? É só chamar construct.
__try
{
typedef __gnu_cxx::__alloc_traits<_Allocator> __traits;
for (; __n > 0; --__n, (void)++__cur)
__traits::construct(__alloc, std::__addressof(*__cur));
return __cur;
}
__catch(...)
{
std::_Destroy(__first, __cur, __alloc);
__throw_exception_again;
}
Certo, o princípio do resize ficou claro; voltemos à questão do início.
2. Evitar a chamada ao construtor padrão¶
Como evitar a chamada ao construtor padrão?
Na verdade, é bem simples: basta bloquear o construct padrão do gcc — e como bloqueá-lo?
Aqui entra o segundo parâmetro do vector: o alocador!
3. Alocador¶
Para resolver esse problema, podemos usar um alocador personalizado. Um alocador personalizado pode controlar o comportamento de construção dos objetos, permitindo-nos escolher se usamos ou não a construção padrão ao chamar resize. Segue uma implementação simples de alocador personalizado, apenas com o código essencial.
template <class T>
class no_init_alloc {
public:
using value_type = T;
// Override construct method to do nothing
template <class U>
void construct(U* p) {
// Do nothing, memory is not initialized
}
};
Basta não fazer nada dentro de construct, e já podemos usá-lo, ou seja:
Assim, obtém-se:
em vez de:
Pronto, você aprendeu?
Fim desta seção
Tópicos relacionados¶
- Idiom de lista de inicialização de classes em C++ | C++那些事
- C++: templates de classe em vez de templates de função | C++那些事
- Idiom copy-and-swap em C++ | C++那些事
- Injeção de dependência em C++ | C++那些事
- C++ enum class enumerações fortemente tipadas | C++那些事
- C++ Header-Only versus separação de implementação | C++那些事
- Idiom de avaliação preguiçosa em C++ | C++那些事
- Idiom de consulta em tabela em C++ | C++那些事
- Ponteiros para membros e type info em C++ | C++那些事
- Idiom Mixin em C++ | C++那些事