2010-04-28 9 views
6

A veces es útil utilizar la dirección de inicio de std::vector y tratar temporalmente esa dirección como la dirección de un búfer asignado regularmente.
Por ejemplo sustituir este:C++: obteniendo la dirección del inicio de un std :: vector?

char* buf = new char[size]; 
fillTheBuffer(buf, size); 
useTheBuffer(buf, size); 
delete[] buf; 

con esto:

vector<char> buf(size); 
fillTheBuffer(&buf[0], size); 
useTheBuffer(&buf[0], size); 

La ventaja de esto es, por supuesto, que la memoria intermedia se cancela la asignación automática y que no tiene que preocuparse por el delete[].

El problema que tengo con esto es cuando el tamaño == 0. En ese caso, la primera versión funciona bien. Un buffer vacío está "asignado" y las funciones subsiguientes no tienen tamaño. Obtienen tamaño == 0.
Sin embargo, la segunda versión falla si size == 0 ya que llamar a buf[0] puede contener correctamente una afirmación de que 0 < size.

¿Existe una alternativa a la expresión &buf[0] que devuelve la dirección del inicio del vector incluso si el vector está vacío?

También consideré usar buf.begin() pero de acuerdo con la norma, ni siquiera se garantiza que devuelva un puntero.

+0

Esto parece un descuido en la biblioteca de STL. C++ le permite asignar 'new T [0]' y devolver un puntero válido para situaciones como esta, pero la mayoría de las implementaciones del STL se reafirman en caso de que esté asignando ese elemento o algo. – AshleysBrain

+0

¿Cómo sabría la diferencia entre '& buf [0]' y 'buf [0] = 1'? – shoosh

Respuesta

8

Supongo que solo tiene que comprobar.

Tal vez una función de utilidad:

template <class T, class Alloc> 
T* data(std::vector<T, Alloc>& vec) 
{ 
    return vec.empty() ? 0 : &vec[0]; 
} 

template <class T, class Alloc> 
const T* data(const std::vector<T, Alloc>& vec) 
{ 
    return vec.empty() ? 0 : &vec[0]; 
} 
+1

1ra observación: ¿vale la pena invertir en 'boost :: addressof' en caso de que' T' tenga un operador '&' sobrecargado? Segunda observación: un segundo parámetro de plantilla 'Alloc' haría que la función sea un poco más universal. –

+1

@ Matthieu: Con respecto a la primera observación: http://stackoverflow.com/questions/2719832/why-is-overloading-operator-prohibited-for-classes-stored-in-stl-containers. No puede almacenar un tipo para el cual '& t' no devuelve su dirección. - Segunda observación agregada a la respuesta. – UncleBens

1

no hay ninguna función para la que, a pesar de que tiene std::basic_stringdata() que hace exactamente lo que necesita.

Vas a tener que usar algo como buf.size()?&buf[0]:0;

1

creo que debe ser seguro en cualquiera de los casos. Creo que las diferencias entre vector :: operator [int] y vector :: at (int) es que la [] sobrecarga del operador especificamente no realiza la comprobación de límites. ¡Usar buf [0] debería estar libre de aserciones!

+0

Tristemente estás equivocado. El vector de MSVC2008 tiene aserciones en 'operator []'. – shoosh

+0

¡Gracias por iluminarme! – acanaday

+4

Como seguimiento, he aprendido que el siguiente '#define _SECURE_SCL 0' deshabilitará este comportamiento. – acanaday

1

Si puede cambiar fillTheBuffer y usar TheBuffer para tomar un par de iteradores, entonces resolverá el problema de la misma manera que la biblioteca estándar lo resolvió.

Cuestiones relacionadas