Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

With std::vector, why is &vec[0] undefined behavior, but vec.data() safe?

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 the std::vector or std::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.

like image 283
Zebrafish Avatar asked Jan 07 '18 13:01

Zebrafish


People also ask

What should I include in std::vector?

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.

Can you use [] for vectors?

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.

How does std::vector Work C++?

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.


3 Answers

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.

like image 106
songyuanyao Avatar answered Oct 07 '22 23:10

songyuanyao


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.

like image 39
Bo R Avatar answered Oct 08 '22 01:10

Bo R


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.

like image 27
StPiere Avatar answered Oct 08 '22 00:10

StPiere