My take on this that no, empty vector does not guarantee that vector::data
returns the underlying buffer even after a call to vector::reserve
.
Reasoning
AFAIK vector::data()
was proposed in issue n. 464 and it looks like that the exact same proposed wording was accepted into the Standard.
Excerpt from the discussion:
To add slightly more convenience to vector and map<Key,T> we should
consider to add
- add vector::data() member (const and non-const version) semantics:
if( empty() ) return 0; else return buffer_;
- ...
Rationale:
- To obtain a pointer to the vector's buffer, one must use either
operator (which can give undefined behavior for empty vectors) or
at() (which will then throw if the vector is empty).
...
Standard draft - 22.3.11.4:
Returns: A pointer such that [data(), data() + size()) is a valid
range. For a non-empty vector, data() == addressof(front()).
It seems that the authors wanted in their rationale to always return nullptr
for an empty container, which would be your case. But the proposed and accepted wording left that ambiguous.
The bottom line is vector::data()
for an empty vector still returns indeterminate value.
Other parts of the Standard ([22.3.11.3]) together guarantee that the buffer will exist after call to reserve but ::data
still might return e.g. nullptr
as per the original discussion.
The safe way
The only safe way seem to be the your solution of:
- Adding dummy element
- Storing
vector::data()
return value as it is now guaranteed to be &v[o]
.
- Deleting the dummy element.
Note, 2.,3. cannot be exchanged, data
could again start return anything.
I am not aware of any downsides resulting from the following wording which would resolve the situation.
Returns: A pointer such that [data(), data() + size()) is a valid
range. For a non-zero capacity vector, data() == addressof(front())
had the vector had a size of at least 1 at the moment of the call.