Implementação de std :: vector independente e compatível com STL

A implementação do std::vector que vem com o Visual Studio 2010 e versões anteriores tem uma particularidade bem conhecida: o método de resize possui a seguinte assinatura (compatível com C ++ 03):

 void resize(size_type new_size, value_type value); 

em vez da assinatura compatível com C ++ 11 que foi usada pela maioria das outras implementações de STL (como STL ou STLport do gcc) muito antes do C ++ 11:

 void resize(size_type new_size, const value_type& value); 

O problema com a primeira variante é que, em algumas situações, ela falhará na compilation se value_type tiver uma especificação de alinhamento:

 struct __declspec(align(64)) S { ... }; std::vector v; // error C2719: '_Val': formal parameter with __declspec(align('64')) won't be aligned 

Esse é um problema bem conhecido sem uma solução satisfatória além de usar uma implementação diferente de std::vector .

Estou à procura de uma implementação de std::vector bem escrita, testada, autocontida e compatível com STL, com uma licença ao estilo MIT que possa include no meu projeto como um contentor de escolha para tipos alinhados.

Eu considerei extraí-lo do STLport ou STL do gcc, mas, sendo totalmente compatível com o padrão, ambos são grandes com muitas dependencies não-triviais.

(Eu ficaria perfeitamente feliz com a implementação de um subconjunto razoável de std::vector que suportaria apenas push_back , clear , capacity , size , reserve , resize , swap e indexação de array.)

Alguma ideia?

Os caras por trás da biblioteca Eigen parecem ter encontrado uma boa solução para o problema de armazenar “tipos excessivamente alinhados” ( como Stephan T. Lavavej os chama ) em um std::vector como implementado no STL do Visual Studio.

Sua implementação parece complicada desnecessariamente (confira as fonts aqui e aqui ) mas a idéia principal é encapsular o tipo que vai para o std::vector com um wrapper fino:

 #include  template  struct wrapper : public T { wrapper() {} wrapper(const T& rhs) : T(rhs) {} }; struct __declspec(align(64)) S { float x, y, z, w; }; int main() { std::vector< wrapper > v; // OK, no C2719 error return 0; } 

Sobre a implementação em Eigen, devo admitir que não entendo muito bem

  • porque eles precisam de Eigen::aligned_allocator_indirection ,
  • por que eles precisam fazer uma exceção para tipos aritméticos em EIGEN_WORKAROUND_MSVC_STL_SUPPORT ,
  • por que eles precisam definir todos esses construtores e operadores em Eigen::workaround_msvc_stl_support ,
  • ou porque eles precisam redefinir resize em sua especialização parcial de std::vector para o alocador Eigen::aligned_allocator_indirection

Pistas bem-vindas. A questão é que esse truque funciona perfeitamente (até onde eu sei) e eu não vejo nada de errado com ele, exceto talvez pela leve deselegância.

A opção mais fácil (e melhor, imho) seria fornecer uma function livre como uma extensão para a interface vector , que faz a coisa certa. As funções necessárias para implementar o resize estão disponíveis na interface pública do std::vector :

 #include  template void resize(std::vector& v, typename std::vector::size_type new_size, T const& val) { if (v.size() < new_size) v.insert(v.end(), new_size - v.size(), val); else if (new_size < v.size()) v.erase(v.begin() + new_size, v.end()); } 

E para consistência também a versão de argumento único:

 template void resize(std::vector& v, typename std::vector::size_type new_size) { v.resize(new_size); // simply forward } 

Se você, no entanto, quiser apenas inserir o novo vetor e nunca se preocupar com a function free ou member, outra opção é simplesmente subclass std::vector :

 #include  #include  template> class myvector : public std::vector { typedef std::vector base; public: typedef typename base::size_type size_type; void resize(size_type new_size){ base::resize(new_size); } void resize(size_type new_size, T const& val){ if (this->size() < new_size) this->insert(this->end(), new_size - this->size(), val); else if (new_size < this->size()) this->erase(this->begin() + new_size, this->end()); } }; 

Observe que também forneci a versão de resize de argumento único, já que a versão de dois argumentos ocultaria todas as versões de class base. Note também que eu precisava prefixar todas as chamadas de function de membro com this-> , uma vez que elas são dependentes da class base std::vector e, como tal, nos argumentos do template.