3
extern const map<string, vector<unsigned char>> my_map;

// get const reference, no copying
const vector<unsigned char> &data = my_map.at("my_key");

// also no copy?
istringstream iss;
iss.rdbuf()->pubsetbuf((char *)data.data(), data.size());

How does the last line work? I saw it on multiple SO answers on how to create a istringstream without copying.

If I understand this correctly, data is a const reference to the element of the map whose key is "my_key". And since at() returns by const reference as well, the values of the vector weren't copied. But since it's a const reference, then I can't change the elements of the vector.

data() returns a const unsigned char*, which I cast to char*. Does this mean that the elements of the array can now be changed? (since its a pointer to a non-const type). Or did the vector get copied when I casted it?

Tirafesi
  • 1,297
  • 2
  • 18
  • 36
  • 2
    Is (or will lead to) Undefined Behaviour. – Richard Critten Dec 09 '19 at 16:23
  • @RichardCritten only if you write into those `char`s, which `std::istringstream` isn't likely to do – Caleth Dec 09 '19 at 16:25
  • Be *very* careful when casting away `const`. Prefer never to do it. If the object you cast `const` away from was initially declared as `const` your code has Undefined Behaviour if you ever modify the object. Casting away `const` is *only* valid if the object in question was originally declared non-const - and that can be extremely difficult to know for sure (and even when you do known it is still a highly suspicious thing to do). – Jesper Juhl Dec 09 '19 at 16:28
  • Note that `basic_stringbuf::setbuf` has implementation-defined behaviour. `pubsetbuf` may well do nothing at all. – Caleth Dec 09 '19 at 16:29
  • 2
    "*Does this mean that the elements of the array can now be changed?*" - not safely, no. The contents of the `map` are const and presumably read-only, casting away constness doesn't change that. Also, the correct C++-style cast would be `const_cast(reinterpret_cast(data.data())` instead of the C style cast `(char*)data.data()`. "*Or did the vector get copied when I casted it?*" - no, it was not copied. – Remy Lebeau Dec 09 '19 at 16:31
  • @Caleth you are absolutely correct and I can see nothing in the docs that even suggests `std::istringstream` can modify the contents of the buffer. – Richard Critten Dec 09 '19 at 16:33
  • @Caleth what exactly does *implementation-defined* mean? What's an "implementation"? – Tirafesi Dec 09 '19 at 16:38
  • We had a similar question recently. I'm not convinced there's any UB here. It's possible I said the opposite at the time. – Lightness Races in Orbit Dec 09 '19 at 16:38
  • 3
    @Tirafesi The "implementation" is your compiler + its friends/associated tools (including standard library). It means "implementation of the C++ standard". Regarding _implementation-defined behaviour_: https://stackoverflow.com/q/2397984/560648 – Lightness Races in Orbit Dec 09 '19 at 16:40

1 Answers1

6

Does this mean that the elements of the array can now be changed?

It means that the type of the pointer is such that it is well-formed to modify the object through the pointer. This means that the compiler is not required to give you a diagnostic message and assuming the entire program is well-formed, the compiler is required to not fail compilation (some restrictions apply).

However, if the pointed object is a const object then the behaviour of modifying it through the pointer to non-const would be undefind.

But the vector elements in this case are non-const (because the template type argument is non-const), so modifying them would be defined. It might be surprising to the reader of the program though. Another matter is whether std::istringstream ever modifies the pointed objects or not.

eerorika
  • 232,697
  • 12
  • 197
  • 326