Why is the output for these two different? Shouldn't both output this-is-a-test?
EDIT: I just put this into an online C++ compiler and I get the correct result, but when I compile using GCC on my machine, it gives the wrong result as above. What is going on?
EDIT 2: I compiled using Clang as well and am getting the same incorrect result. But on online compilers it is showing the correct result.
C++11: The pointer returned points to the internal array currently used by the string object to store the characters that conform its value.
The pointer returned may be invalidated by further calls to other member functions that modify the object.
If the temp does no reallocate on each input, then the array remains same and all four calls return same address.
If the temp does reallocate, then previous pointers become invalid.
I just put this into an online C++ compiler and I get the correct result
Which online compiler? It seems unusual to me for it to give what you call the "correct" result, although it is possible (if c_str() copied the data somewhere or if temp used different storage for each string, which seems wasteful). But this cannot be relied on. In fact, the storage has almost certainly been freed.
The vector of const char* is only storing the address of a string, not the string itself. You are (potentially at least) storing the exact same address in all of the elements, the address of temp.c_str(). That's why you only see the last string. You need to allocate space for the string to store separate strings.
That site uses gcc 4.9.2 whereas the current version is 10.2. Apparently that version inefficiently stores the strings in different memory each time, even if the current memory is large enough to hold the new string. In fact, the strings are small enough to be stored in the string structure itself (small string optimization), which is what the version I'm using does.
Is there an easier way to input into C-strings using std::string::c_str without having to worry about manually dynamically allocating a char array and copying it over?
Apparently that version inefficiently stores the strings in different memory each time, even if the current memory is large enough to hold the new string.
Pre-GCC 5.1 std::string was implemented using CoW. But then the C++11 standard (indirectly) banned copy-on-write implementations in order to better support concurrency. Rationale here: https://wg21.link/n2534
Is there an easier way to input into C-strings using std::string::c_str without having to worry about manually dynamically allocating a char array and copying it over?
Yes. Just use std::string. That's what it's for. It handles the allocation/deallocation for you.
Yes. Just use std::string. That's what it's for. It handles the allocation/deallocation for you.
I am well aware of this alternative. Unfortunately this isn't a possibility for me. I have to access Linux functions such as fork() and exec(), which expect C-style strings, in a C++ program. I have managed to make some workarounds for it, such as using std::vector<std::string> to store a buffer (to be passed as the "argv" parameter in exec(), to which I then perform a std::transform() on to convert it to a std::vector<constchar*>, which I then take and perform a const_cast on it after retrieving the raw buffer using the std::vector::data() member function order to pass it as an an argument to exec. Obviously, this is a very messy solution.
@seeplus:
The .c_str() returns a pointer and that is what started this thread.
@dutch:
In function 'void my_exec(std::vector<std::basic_string<char> >&)':
9:41: error: invalid conversion from 'const char*' to 'std::vector<char*>::value_type {aka char*}' [-fpermissive]
One can add explicit cast:
1 2
for (auto& s: v)
w.push_back( const_cast<char*>(s.data()) );
There are many compilers that support C++ standards to varying level. GCC supports more than one C++ standard (with and without GNU extensions). Each version of GCC has some standard as default, but can be told (the -std= option) to use different standard. Hence (default) behaviour can differ.
Pre-C++11 was less specific about the .c_str() / .data().
The .c_str() returns a pointer and that is what started this thread.
The OP was regarding vector of pointers, not passing arguments to functions.
@dutch Shouldn't the second param to execvp be the address of the second element of w - not the first as that's the command? Also .data() does not guarantee that the returned array is null-terminated.
@keskiverto, I compiled as c++17 with full warnings (as usual) with g++ 9.3, and for whatever reason it worked, although it won't compile as c++11 or c++14.
seeplus wrote:
Shouldn't the second param to execvp be the address of the second element of w
No, the first argument is also the command. It just lets the program know what filename it was started with.
Also, your code will not compile for me, no matter what standard I choose.
Clearly this is fiddly business. :-)