Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting std::string ** to char *** and it happens to work. How?

Tags:

c++

Consider the following code:

std::vector<std::string> foo{{"blee"}, {"bleck"}, {"blah0000000000000000000000000000000000000000000000000000000000000000000000000000000000"}};
std::string *temp = foo.data();
char*** bar = reinterpret_cast<char***>(&temp);

for (size_t i = 0; i < foo.size(); ++i){
    std::cout << (*bar)[i] << std::endl;
}

Clearly this is sketchy code, but it happens to work.

http://ideone.com/2XAJYR

I would like to know why it works? Are there some strange rules of C++ I don't know about? Or is it just bad code and undefined behaviour?

I made one of the strings huge in case there was some small-string optimization going on.

Adapted from: Cast a vector of std::string to char***

like image 536
Neil Kirk Avatar asked Mar 13 '15 12:03

Neil Kirk


People also ask

Can you set a string to a char * C++?

You can't really "assign a string" to a char * , because although a char* parameter is sometimes referred to as a "string parameter", it isn't actually a string, it's a pointer (to a string).

Should I use std::string or * char?

Use std::string when you need to store a value. Use const char * when you want maximum flexibility, as almost everything can be easily converted to or from one.

Is std::string a char *?

We know that both string::c_str or string::data functions returns const char*. To get a non-const version, we can use the const_cast operator, which removes the const attribute from a class. This works in constant time as no copying is involved.

Is char * Same as string?

The difference between a string and a char* is that the char* is just a pointer to the sequence. This approach of manipulating strings is based on the C programming language and is the native way in which strings are encoded in C++.


3 Answers

It is very much undefined behaviour.

It will appear to "work" if the string implementation happens to contain a pointer to the string data as its only data member, so that an array of string has the same memory layout as an array of char*. That is the case for at least one popular implementation (GNU), but is certainly not something you can rely on.

like image 112
Mike Seymour Avatar answered Oct 23 '22 02:10

Mike Seymour


The behaviour depends on your STL implementation (just revise std::vector and std::string source code). Occasionaly, you have the string impl that stores (as other participants mentioned) pointer to chars buffer as a member.

It's not a secret that one shoudn't rely on incapsulated details of implementation due to undefined behaviour it causes.

like image 40
Michael Grigoriev Avatar answered Oct 23 '22 00:10

Michael Grigoriev


After Neil Kirk mentioned this in a comment on the answer that originally sparked all this, I looked it up.

string is a specialization of basic_string on all implementations.

Now I only have access to Visual Studio's 2013 version of xstring.h (here Microsoft implements basic_string) so this may be different for other versions or compilers. But in xstring.h basic_string inherits from _String_alloc which inherits from _String_val.

_String_val is actually the first in the inheritance chain which has any member variables. It's first member variable, _Bx, is a union which will translate to a char* for string (not for wstring).

So when a string is cast to a char* on Visual Studio 2013 it is a char* which begins pointing to the member variable: _Bx Since _Bx is actually a '\0'-terminated char* you can cout it and it behave's properly.

Now what I didn't know, and what all this research taught me, is that _String_val also contains a size variable, _Mysize, and a reserved size, _Myres. If either of those had been declared in _String_val before _Bx this would have outputted gibberish at the start of cout's output each line.

I'd conclude by conceding that as is mentioned by the other answers this behavior is implementation dependent, and may not work across diferent versions or platforms.

like image 2
Jonathan Mee Avatar answered Oct 23 '22 02:10

Jonathan Mee