2012-02-23 10 views
7

La implementación de std::vector que se incluye con Visual Studio 2010 y versiones anteriores tiene una particularidad bien conocida: el método resize tiene la siguiente firma (compatible con C++ 03) :Implementación autónoma compatible con STL de std :: vector

void resize(size_type new_size, value_type value); 

en lugar de la firma C++ 11-compatible que se ha utilizado por la mayoría de otras implementaciones STL (como STL de gcc o STLport) mucho antes de C++ 11:

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

el problema con la primera variante es que, en alguna situación ciones, se producirá un error de compilación si value_type tiene una especificación de alineación:

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

Este es un problema wellknown con ninguna solución satisfactoria aparte de usar una implementación diferente de std::vector.

Busco un bien escrito bien probado, autónomo y con capacidad para un STL aplicación, de std::vector con una licencia estilo MIT que podría caer en mi proyecto como un contenedor de elección para Alineados tipos.

Consideré extraerlo de STLport o STL de gcc pero, al ser totalmente compatibles con las normas, son grandes con muchas dependencias no triviales.

(me gustaría que perfectamente feliz con una implementación de un subconjunto razonable de std::vector que sólo apoyaría push_back, clear, capacity, size, reserve, resize, swap y la indexación de matrices.)

¿Alguna idea?

+0

No veo cómo el método '.resize()' hace que la declaración 'std :: vector v;' falle. La instanciación de una plantilla de clase no instancia sus métodos, solo los utilizados. (Es decir, ctor y dtor predeterminados en este caso). – MSalters

+0

Supongo que el error se emite durante el análisis ... Tenga en cuenta que estamos hablando de un verdadero problema específico del compilador aquí. –

Respuesta

8

Los chicos detrás de la biblioteca Eigen parecen haber encontrado una buena solución para el problema del almacenamiento de los "tipos alineados excesivamente" (as Stephan T. Lavavej call them) en un std::vector como se aplica en STL de Visual Studio.

Su aplicación parece innecesario complicada (marque las fuentes here y here) pero la idea principal es encapsular el tipo que va en el std::vector con una envoltura delgada:

#include <vector> 

template <typename T> 
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<S> > v; // OK, no C2719 error 
    return 0; 
} 

Sobre la implementación de Eigen, me debe admitir que no entiendo muy bien

  • por qué necesitan Eigen::aligned_allocator_indirection,
  • por qué tienen que hacer una n excepción para los tipos aritméticos en EIGEN_WORKAROUND_MSVC_STL_SUPPORT,
  • por qué tienen que definir todos estos constructores y operadores en Eigen::workaround_msvc_stl_support,
  • o por qué se necesitan redefinir resize en su especialización parcial de std::vector para el asignador Eigen::aligned_allocator_indirection ...

Se agradecen las pistas. El punto es que este truco funciona perfectamente (por lo que yo sé) y no veo nada malo en él, aparte de la ligera falta de elegancia.

1

La opción más fácil (y la mejor, imho) sería proporcionar una función gratuita como una extensión a la interfaz vector, que hace lo correcto. Las funciones que se necesitan para implementar resize están todos disponibles en la interfaz pública de std::vector:

#include <vector> 

template<class T, class Alloc> 
void resize(std::vector<T, Alloc>& v, 
    typename std::vector<T, Alloc>::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()); 
} 

y por coherencia también la única versión argumento:

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

Si, sin embargo, sólo quieren desplegable en el nuevo vector y nunca preocuparse de función libre o miembro, otra opción es simplemente una subclase std::vector:

#include <vector> 
#include <memory> 

template<class T, class Alloc = std::allocator<T>> 
class myvector 
    : public std::vector<T, Alloc> 
{ 
    typedef std::vector<T, Alloc> 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()); 
    } 
}; 

Tenga en cuenta que también proporcioné la versión de argumento único de resize, ya que la versión de dos argumentos ocultaría todas las versiones de clase base. También tenga en cuenta que necesitaba para prefijar todas las llamadas a funciones miembro con this->, ya que dependen de la clase base std::vector, y como tal en los argumentos de la plantilla.

+0

+1, aunque me gustaría señalar que la creación de subclases es límite ... –

+1

Subclases 'std :: vector' fue uno de mis primeros enfoques, lamentablemente aún no se compila porque, al final,' std :: vector' todavía se instancia . –

+1

@ FrançoisBeaune: Ah, eso es relativamente desafortunado. :/Intente comentar la versión 'std :: vector', o simplemente corrija la firma. : P FWIW, VS11 aún no soluciona este problema. – Xeo

Cuestiones relacionadas