I've been reading through the FAQ at isocpp.org at "Link here" and came across the caution that with an std::vector
:
std::vector<int> v;
auto a = &v[0]; // Is undefined behaviour but
auto a = v.data(); // Is safe
From the actual site:
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
}
Also, using
&v[0]
is undefined behavior if thestd::vector
orstd::array
is empty, while it is always safe to use the.data()
function.
I'm not sure I've understood this exactly. ::data()
returns a pointer to the beginning of the array, and &[0]
returns the address of the beginning. I'm not seeing the difference here, and I don't think that &[0]
is dereferencing anything (i.e., is not reading the memory at element 0). On Visual Studio in debug build accessing subscript [0]
results in an assertion failed, but in release mode it doesn't say anything. Also the addresses in both cases is 0 for the default constructed vector.
Also I don't understand the comment about ::begin()
not guaranteed to be the same as ::operator[0]
. I assumed that for a vector the raw pointer in the begin()
iterator, ::data()
, and &[0]
were all the same value.
To create a vector in C++, you first have to include the vector library. You do this by adding the line #include <vector> at the top of your file. This line goes after the line #include <iostream> and any other header files you've included in your program. The std::vector is included in the #include <vector> library.
Access and update element in vector using [] As, operator [] returns a reference to the element in vector, so we can change the content of vector too using operator [] i.e.
Vectors are the same as dynamic arrays with the ability to resize itself automatically when an element is inserted or deleted, with their storage being handled automatically by the container. Vector elements are placed in contiguous storage so that they can be accessed and traversed using iterators.
I'm not seeing the difference here
&v[0]
is same as &(v[0])
, i.e. get the address from the 1st element of v
. But when v
is empty there're no elements at all, v[0]
just leads to UB, it's trying to return a non-existent element; trying to get the address from it doesn't make sense.
v.data()
is always safe. It will return the pointer to the underlying array directly. When v
is empty the pointer is still valid (it might be null pointer or not); but note that dereferencing it (like *v.data()
) leads to UB too, the same as v[0]
.
Also I don't understand the comment about
::begin()
not guaranteed to be the same as::operator[0]
std::vector::begin
will return an iterator with type std::vector::iterator
, which must satisfy the requirement of RandomAccessIterator. It might be a raw pointer, but it doesn't have to be. It's acceptable to implement it as a class.
The information missing in your question for your example to be more understandable is that void f(Foo* array, unsigned numFoos);
Calling .begin()
on your vector of Foo
is not guaranteed to be a pointer. But some implementations might behave like it enough for it to work.
In the empty vector case, v.data()
, returns a pointer but you don't know what it points to. It could be a nullptr, but that is not guaranteed.
It all comes down to one simple thing: You can add or subtract an integral value to the pointer, but trying to dereference an invalid pointer is undefined behaviour.
Say for example,
int a[10];
int* p = a;
int* q = p + 10; // This is fine
int r = *(p + 10) // This is undefined behaviour
In your example: v[0]
is the same as *(v's internal pointer+0)
, and this is a problem if the vector is empty.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With