Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the const overload of std::string::data still restricted in modern C++?

Tags:

c++

c++14

std::basic_string::data has a requirement under its specification.

[string.accessors] (emphasis mine)

const charT* c_str() const noexcept;
const charT* data() const noexcept;

1 Returns: A pointer p such that p + i == &operator[](i) for each i in [0, size()].

2 Complexity: Constant time.

3 Requires: The program shall not alter any of the values stored in the character array.

This made sense in C++03 for c_str because it need not have returned a pointer to the actual string buffer, and for data because COW was a possible implementation strategy. Even if the buffer wasn't really const, modifying data would have interfered with the invariants of COW.

But since C++11 COW is disallowed, c_str and data return the same pointer, and it's to the very buffer operator[] would allow to modify. Why then is modifying the pointer via const_cast<CharT*>(s.data()) still explicitly undefined behavior? Is there a practical reason?

like image 497
StoryTeller - Unslander Monica Avatar asked Jun 03 '19 20:06

StoryTeller - Unslander Monica


1 Answers

I'm not talking about a const std::string, but a non-const one.

And that right there is why that statement exists (and continues to exist even in C++17, when a non-const data was added). Because data doesn't know that.

In a small-string optimized string implementation, the string object itself stores an array of characters. If that string object is declared const, then so too are its subobjects. Modifying objects declared as const is UB.

By contrast, vector::data has no such statement, because a const vector always heap-allocates its array. So while the array is logically const from the outside, it is technically well-defined (but you really, really shouldn't) to const_cast the return value from a const vector::data, because you're modifying an object that was not created as const.

If basic_string::data had no such statement, an SSO-based implementation would be impossible, because it would be legal to modify the elements of a const string, just like it's legal to modify the elements of a const vector. But it can't be legal to modify it, because it might be a const object whose data is stored internally.

like image 173
Nicol Bolas Avatar answered Nov 15 '22 04:11

Nicol Bolas