26

In the C++ reference of c_str() in std::string the following appears:

Return value
Pointer to the underlying character storage.
data()[i] == operator[](i) for every i in [0, size()) (until C++11)
data() + i == &operator[](i) for every i in [0, size()] (since C++11)

I do not understand the difference between the two, except for the range increase by one element since C++11.

Isn't the former statement data()[i] == operator[](i) also true for the latter?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Chiel
  • 6,006
  • 2
  • 32
  • 57

3 Answers3

20

Except for the range increment by one element since C++11, there is still a big difference between:

data()[i] == operator[](i)

and:

data() + i == &operator[](i)

That main difference is the & operator in the prototypes.

The old prototype, allowed for copy to be made when a write operation would occur, since the pointer returned could point to another buffer than the one holding the original string.

The other difference in the prototypes between data()[i] and data() + i, is not critical, since they are equivalent.


A difference between C++ and C++11 is that in the former, an std::string was not specified explicitly by the standard for whether it would have a null terminator or not. In the latter however, this is specified.

In other words: Will std::string always be null-terminated in C++11? Yes.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 1
    Arguably, an implementation could reserve space for the terminator, and lazily null it from `c_str()`. Not that that would be a reasonable thing to do, of course. – Sneftel Aug 21 '17 at 17:45
  • Nah, it's an almost painfully pedantic point. Jus' saying. :) – Sneftel Aug 21 '17 at 17:48
9

Note the closing bracket difference:

[0, size())

[0, size()]

First stands for exclusive range (that is item at size index is not included) while second stands for inclusive range (that is item at size index is included) Before C++ the precense of terminating null was not handled in this case, while in C++11 accessing character at size() position is well-defined.

As for difference between data()[i] == operator[](i) and data() + i == &operator[](i) the second one applies more restrictions on potential implementation. In first case a pointer to buffer returned by data() may be different from the pointer to buffer where a value the reference to which returned by operator [] is stored. This could happen when a new buffer was created after invocation of non-const-qualified operator[] of copied string.

Community
  • 1
  • 1
user7860670
  • 35,849
  • 4
  • 58
  • 84
0

Prior to C++11, it was unspecified whether the string data was null-terminated or not. C++11 says it must be null-terminated.

  • But why the notation difference from `data()[i]` to `data() + i`? – Chiel Aug 20 '17 at 12:47
  • I thought VTT explained that - it's the difference difference between half-open and open ranges. –  Aug 20 '17 at 12:48
  • I don't get that. Isn't `data()[i]` identical to `*(data() + i)`? – Chiel Aug 20 '17 at 12:49
  • But c_str already existed and had to run in constant time, wouldn't this imply that the null terminator is present? – Nir Friedman Aug 20 '17 at 12:50
  • @Nir All implementations I'm aware of provided it, but the C++98 Standard didn't specify that there must be one. –  Aug 20 '17 at 12:51