1

vec.data() usually is &vec[0] except when vec.empty() . In the latter case, vec.data() might be a nullptr.

Question: If I call vec.reserve with a sufficient size, I know that &vec[0] won't change anymore. But for the edge case of an initially-empty vector, can I rely on vec.data() being stable as well?

Rationale: in a ctor I want to initialize a const T* const to vec.data(). None of the class members will let vec grow past the reserved size. I could add a temporary single element just so I could write &vec[0], but that seems a bit contrived.

MSalters
  • 173,980
  • 10
  • 155
  • 350

1 Answers1

0

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

  1. add vector::data() member (const and non-const version) semantics: if( empty() ) return 0; else return buffer_;
  2. ...

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:

  1. Adding dummy element
  2. Storing vector::data() return value as it is now guaranteed to be &v[o].
  3. 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.

Quimby
  • 17,735
  • 4
  • 35
  • 55