read - vector get c++
Con std:: vector, ¿por qué es & vec[0] comportamiento indefinido, pero vec.data() es seguro? (3)
He estado leyendo las preguntas frecuentes en isocpp.org en "Enlace aquí" y encontré la advertencia de que con std::vector
:
std::vector<int> v;
auto a = &v[0]; // Is undefined behaviour but
auto a = v.data(); // Is safe
Desde el sitio real:
void g()
{
std::vector<Foo> v;
// ...
f(v.begin(), v.size()); // Error, not guaranteed to be the same as &v[0]
↑↑↑↑↑↑↑↑↑ // Cough, choke, gag; use v.data() instead
}
Además, usar
&v[0]
es un comportamiento indefinido sistd::vector
ostd::array
está vacío, mientras que siempre es seguro usar la función.data()
.
No estoy seguro de haber entendido esto exactamente. ::data()
devuelve un puntero al comienzo de la matriz, y &[0]
devuelve la dirección del comienzo. No veo la diferencia aquí, y no creo que &[0]
esté desreferenciando nada (es decir, no está leyendo la memoria en el elemento 0). En Visual Studio en depuración, el acceso al subíndice [0]
da como resultado una aserción fallida, pero en el modo de lanzamiento no dice nada. También las direcciones en ambos casos son 0 para el vector construido por defecto.
Además, no entiendo que el comentario sobre ::begin()
no garantice ser el mismo que ::operator[0]
. Supuse que para un vector, el puntero sin formato en el iterador begin()
, ::data()
y &[0]
tenían el mismo valor.
No veo la diferencia aquí
&v[0]
es igual que &(v[0])
, es decir, obtiene la dirección del primer elemento de v
. Pero cuando v
está vacío no hay elementos en absoluto, v[0]
solo lleva a UB, está intentando devolver un elemento inexistente; tratar de obtener la dirección no tiene sentido.
v.data()
es siempre seguro. Devolverá el puntero a la matriz subyacente directamente. Cuando v
está vacío, el puntero sigue siendo válido (puede ser un puntero nulo o no); pero tenga en cuenta que desreferenciarlo (como *v.data()
) también conduce a UB, al igual que v[0]
.
Además, no entiendo el comentario sobre
::begin()
no garantizado que sea el mismo que::operator[0]
std::vector::begin
devolverá un iterador con tipo std::vector::iterator
, que debe cumplir los requisitos de RandomAccessIterator . Puede ser un puntero sin formato, pero no tiene que ser así. Es aceptable implementarlo como una clase.
La información que falta en su pregunta para que su ejemplo sea más comprensible es ese void f(Foo* array, unsigned numFoos);
Llamar a .begin()
en su vector de Foo
no garantiza que sea un puntero . Pero algunas implementaciones se pueden comportar lo suficiente como para que funcione.
En el caso de vector vacío, v.data()
, devuelve un puntero pero no sabe a qué apunta. Podría ser un nullptr, pero eso no está garantizado.
Todo se reduce a una cosa simple: puede agregar o quitar un valor integral al puntero, pero intentar desreferenciar un puntero no válido es un comportamiento indefinido.
Diga por ejemplo,
int a[10];
int* p = a;
int* q = p + 10; // This is fine
int r = *(p + 10) // This is undefined behaviour
En su ejemplo: v[0]
es lo mismo que *(v''s internal pointer+0)
, y este es un problema si el vector está vacío.