@eerorika Seemed to answer the question, but I wanted to give some insight on why this code still works.
For this specific example, I'd say this isn't so much a case of C++ UB, but rather a case of misusing an API (the API being std::vector). Depending on how std::vector is implemented, the snippet of code may not lead to any C++ UB.
Under the hood, a vector may just be implemented as a malloc'd pointer at a certain capacity:
template <typename T>
class vector {
public:
// Methods ...
private:
T *buffer_; // internal buffer
size_t size_; // # of elements
size_t capacity_; // Actual size of the buffer
};
std::vector::clear() doesn't change the capacity of the vector. So it could just be that for a clear() implementation, neither the capacity nor buffer change, but size_ is just set to 0. In this case, sanitizers wouldn't report a dangling reference with auto &first = v[0]; since (internally to the vector) it's actually pointing to valid malloc'd memory still.
This would perhaps lead to some UB if more stuff was done on the internal buffer. For example:
#include <iostream>
#include <vector>
int main() {
auto v = std::vector<int>();
v.push_back(20);
auto &first = v[0];
auto vector_ref = &v;
vector_ref->clear();
vector_ref->shrink_to_fit(); // Suggest to vector that we want to take back some memory
std::cout << first;
}
The shrink_to_fit can (but isn't guaranteed to) reallocate the internal vector buffer and cause first to be a dangling reference. Compiling with clang++ v8 and ASan can show that (if a relocation occured), we'd be accessing previously free'd memory on the heap:
$ clang++ /tmp/test.cpp -std=c++17 -fsanitize=address
$ ./a.out
=================================================================
==228989==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000010 at pc 0x0000004fc531 bp 0x7fff8bfcfb70 sp 0x7fff8bfcfb68
... Rest of the error
Edit: To tie this back to the original question, sanitizers and warnings for checking UB are good for checking "Am I using C++ correctly?", but when it comes to questions regarding classes or APIs, this is more a question of "Am I using this API correctly?". Checking wether or not you are using the API correctly is up to the API itself (for example, indexing using operator[] doesn't actually do bounds checking, but at() does and would throw an exception.