C++ string.c_str() - c++

If using g++ and clang++, I get ++my string==my string##my string--. While MSVC and Intel Compiler, it is ++==my string##my string--.
Why?
#include <string>
#include <iostream>
using namespace std;
string test()
{
string s0 = "my string";
return s0;
}
int main()
{
string s = test();
const char* s1 = test().c_str();
const char* s2 = s.c_str();
cout << "++" << s1 << "==" << s2 << "##" << test().c_str() << "--" << endl;
return 0;
}
Is it an undefined behavior?

In a comment, you asked:
Why test().c_str() can work but s1 not?
test().c_str() works only in some contexts, not all contexts.
std::cout << test().c_str() << std::endl;
is guaranteed to work since the temporary returned by test() is required to stay alive until the execution of the statement is complete.
On the other hand,
char const* s1 = test().c_str();
std:cout << s1 << std::endl;
is undefined behavior since the temporary is not required to live beyond completion of execution of the first line.

Related

g++: crash when accessing ostringstream::str().c_str()

The code below fails on gcc 9.4.0. Is this just a bug, or have I done something stupid?
log declares an ostringstream object, writes a filename and a line number to it, and attempts to do something with the object's underlying str().c_str().
Valgrind shows this crashing at the pointer access. The output I get is:
foo.cc, line 100
cptr is at 0x55c45e8f00c0, and is
#include <iostream>
#include <sstream>
#include <cstdarg>
using std::cout;
using std::ostringstream;
void log(const char *fname, int lineno) {
ostringstream outstr;
outstr << fname << ", line " << lineno;
cout << outstr.str() << '\n'; // prints Ok
const char *cptr = outstr.str().c_str();
cout << "cptr is at " << (void*) cptr << ", and is " << cptr; // crash
}
int main() {
log("foo.cc", 100);
}
std::ostringstream::str() returns a temporary string which will be destructed at the end of the line, this then means cptr is a dangling pointer.
Try:
std::string str = outstr.str();
const char *cptr = str.c_str();
cout << "cptr is at " << (void*) cptr << ", and is " << cptr;

Accessing elements in a std::string with pointers

How can I access individual elements in a std::string with pointers? Is it possible without type casting to a const char *?
#include <iostream>
#include <string>
using namespace std;
int main() {
// I'm trying to do this...
string str = "This is a string";
cout << str[2] << endl;
// ...but by doing this instead
string *p_str = &str;
cout << /* access 3rd element of str with p_str */ << endl;
return 0;
}
There are two ways:
Call the operator[] function explicitly:
std::cout << p_str->operator[](2) << '\n';
Or use the at function
std::cout << p_str->at(2) << '\n';
Both of these are almost equivalent.
Or dereference the pointer to get the object, and use normal indexing:
std::cout << (*p_str)[2] << '\n';
Either way, you need to dereference the pointer. Through the "arrow" operator -> or with the direct dereference operator * doesn't matter.

what is the name of this new c++ syntax? [duplicate]

This question already has answers here:
What is the operator "" in C++?
(2 answers)
Closed 5 years ago.
I just saw a new C++ syntax like:
x = "abc"s;
From context I guessed that this means x was assigned a string "abc", I would like to know the name of this new syntax, and is there any similar syntax in C++1z?
Yes, they've been around since C++11. They're called user-defined literals. This specific literal was standardized in C++14, however, it is easy to roll your own.
#include <string>
#include <iostream>
int main()
{
using namespace std::string_literals;
std::string s1 = "abc\0\0def";
std::string s2 = "abc\0\0def"s;
std::cout << "s1: " << s1.size() << " \"" << s1 << "\"\n";
std::cout << "s2: " << s2.size() << " \"" << s2 << "\"\n";
}
For example, to make your own std::string literal, you could do (note, all user-defined literals must start with an underscore):
std::string operator"" _s(const char* s, unsigned long n)
{
return std::string(s, n);
}
To use the example I gave, simply do:
#include <iostream>
#include <string>
std::string operator"" _s(const char* s, unsigned long n)
{
return std::string(s, n);
}
int main(void)
{
auto s = "My message"_s;
std::cout << s << std::endl;
return 0;
}

why std::scan_is emits runtime error in visual studio compiler?

The example here emits a runtime error with memory access violation in Visual Studio 2013.
#include <locale>
#include <iostream>
#include <iterator>
int main()
{
auto& f = std::use_facet<std::ctype<char>>(std::locale(""));
// skip until the first letter
char s1[] = " \t\t\n Test";
const char* p1 = f.scan_is(std::ctype_base::alpha, std::begin(s1), std::end(s1));
std::cout << "'" << p1 << "'\n";
// skip until the first letter
char s2[] = "123456789abcd";
const char* p2 = f.scan_is(std::ctype_base::alpha, std::begin(s2), std::end(s2));
std::cout << "'" << p2 << "'\n";
}
Why is that? Wrong implementation from the compiler?
The line auto& f = std::use_facet<std::ctype<char>>(std::locale("")); causes the error. The reference f is an alias for a null object. It seems that this implementation works for gcc C+11 and above compilers but it does not work in Microsoft compilers. Thus the right implementation in Visual Studio 2013 & 2015 which i tested, is:
#include "stdafx.h"
#include <locale>
#include <iostream>
#include <iterator>
int main()
{
std::locale loc(std::locale(""));
//auto& f = std::use_facet<std::ctype<char>>(std::locale(""));
auto& f = std::use_facet<std::ctype<char>>(loc);
// skip until the first letter
char s1[] = " \t\t\n Test";
const char* p1 = f.scan_is(std::ctype_base::alpha, std::begin(s1), std::end(s1));
std::cout << "'" << p1 << "'\n";
// skip until the first letter
char s2[] = "123456789abcd";
const char* p2 = f.scan_is(std::ctype_base::alpha, std::begin(s2), std::end(s2));
std::cout << "'" << p2 << "'\n";
}

try to understand the pointers maintained by a string object

Ran a simple program to test the pointer in string object, got
0x1875028
Hello
0x1875058 0x1875028
Hello world!!!
0x1875028
I am trying to understand why would s.c_str() change value after erase() call but not st.c_str().
Here is the simple code:
#include <vector>
#include <unordered_map>
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
string st;
void dum() {
string s("Hello world!!!");
printf("%p\n", s.c_str());
st = s;
s.erase(6);
cout << s << endl;
printf("%p %p\n", s.c_str(), st.c_str());
}
int main(int argc,char *argv[]) {
dum();
cout << st << endl;
st.erase(6);
printf("%p\n", st.c_str());
return 0;
}
This actually depends on the version you're using. See, for example Is std::string refcounted in GCC 4.x / C++11?. When you write for two strings, a, and b
a = b;
Then there's a question of whether they're internally pointing to the same object (up until one of them is modified). So either behavior your program exhibits is not very surprising.
First of all, I think this goes under the implementation details umbrella.
I tried that with VS2013.
After you call erase(), the string pointer returned by c_str() is not changed because I think the internal string implementation just updates the end of string (changing some internal data member), instead of doing a new heap reallocation for the internal string buffer (such an operation would likely return a new pointer value).
This is a behavior that I noted both for your local s string and the global st string.
Note that the STL implementation that comes with VS2013 doesn't use COW (COW seems to be non-standard C++11 compliant), so when you copy the strings with st = s, you are doing a deep copy, so the two strings are completely independent and they point to different memory buffers storing their respective string contents. So, when you erase something from one string, this operation is in no way reflected to the other copied string.
Sample Code
#include <iostream>
#include <string>
using namespace std;
// Helper function to print string's c_str() pointer using cout
inline const void * StringPtr(const string& str)
{
// We need a const void* to make cout print a pointer value;
// since const char* is interpreted as string.
//
// See for example:
// How to simulate printf's %p format when using std::cout?
// http://stackoverflow.com/q/5657123/1629821
//
return static_cast<const void *>(str.c_str());
}
string st;
void f() {
string s{"Hello world!!!"};
cout << "s.c_str() = " << StringPtr(s) << '\n';
st = s;
s.erase(6);
cout << s << '\n';
cout << "s.c_str() = " << StringPtr(s)
<< "; st.c_str() = " << StringPtr(st) << '\n';
}
int main() {
f();
cout << st << endl;
st.erase(6);
cout << "st.c_str() = " << StringPtr(st) << '\n';
}
Output
C:\Temp\CppTests>cl /EHsc /W4 /nologo test.cpp
test.cpp
C:\Temp\CppTests>test.exe
s.c_str() = 0036FE18
Hello
s.c_str() = 0036FE18; st.c_str() = 01009A40
Hello world!!!
st.c_str() = 01009A40