Difference in c_str function specification between C++03 and C++11
Asked Answered
L

3

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?

Lazos answered 20/8, 2017 at 12:40 Comment(3)
the previous wording allowed for copy on write implementations, which might have to make a copy for c_str()Plastid
I would say that data()[size()] is UB.Outwear
@Outwear Not in case of the C++11 implementation.Lazos
E
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.

Execration answered 20/8, 2017 at 12:48 Comment(2)
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.Eddaeddana
Nah, it's an almost painfully pedantic point. Jus' saying. :)Eddaeddana
D
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.

Darelldarelle answered 20/8, 2017 at 12:45 Comment(0)
M
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.

Mccollum answered 20/8, 2017 at 12:44 Comment(5)
But why the notation difference from data()[i] to data() + i?Lazos
I thought VTT explained that - it's the difference difference between half-open and open ranges.Mccollum
I don't get that. Isn't data()[i] identical to *(data() + i)?Lazos
But c_str already existed and had to run in constant time, wouldn't this imply that the null terminator is present?Haberman
@Nir All implementations I'm aware of provided it, but the C++98 Standard didn't specify that there must be one.Mccollum

© 2022 - 2024 — McMap. All rights reserved.