I have an issue using stringstreams
When I run this code the first printf is fine but at some point it gets contaminated and prints out a shorter string.
string CJpsURI::getURIwithSipIpPort()
{
stringstream ss;
ss << "sip:" << m_ipAddr << ":" << m_portAddr;
string out = ss.str();
}
main() {
CJpsURI localIp();
localIp.setIpPort("192.168.88.1", 5060);
char *s = localIp.getURIwithSipIpPort().c_str();
printf("This is the sip port: %s", s); // this may be ok -- sip:192.168.88.1:5060
// do some stuff
printf("This is the sip port: %s", s); // wrong; -- sip:192.168.8/030/004
}
It almost appears that the *s is pointing to the out string on the stack which gets destroyed. But that should not be happening since I am returning out and not a reference to out.
But this seems to work.
string CJpsURI::getURIwithSipIpPort()
{
string out = (boost::format("sip:%1%:%2%") % m_ipAddr % m_portAddr).str();
return out;
}
main() {
CJpsURI localIp();
localIp.setIpPort("192.168.1.1", 5060);
char *s = localIp.getURIwithSipIpPort().c_str();
printf("This is the sip port: %s", s); // this may be ok
// do some stuff
printf("This is the sip port: %s", s); // this will be ok too;
}
Any ideas would be appreciated
You have two problems:
As remyabel and Galik pointed out: Your function does not return. So I would Concur with Galik that you need to adapt your function to:
string CJpsURI::getURIwithSipIpPort()
{
stringstream ss;
ss << "sip:" << m_ipAddr << ":" << m_portAddr;
return ss.str();
}
A char* points to an array of chars. Here you want the array found inside the string returned by getURIwithSipIpPort. But that memory will be released as soon as this line ends! There is nothing hanging on to it. So what you really need to do is:
string s{localIp.getURIwithSipIpPort()};
The C++ standard says:
§ 6.7/2 [..] Flowing off the end of a function is equivalent to a
return with no value; this results in undefined behavior in a
value-returning function.
The second problematic statement is:
char *s = localIp.getURIwithSipIpPort().c_str();
First, the conversion from const char* to char* is deprecated. Use const char*. Second, don't do this in the first place. If you want to prolong the lifetime of a temporary, use a const reference.
const std::string& s = localIp.getURIwithSipIpPort().c_str();
Your first function does not return anything:
string CJpsURI::getURIwithSipIpPort()
{
stringstream ss;
ss << "sip:" << m_ipAddr << ":" << m_portAddr;
string out = ss.str(); // This does not get returned!
}
Try this:
string CJpsURI::getURIwithSipIpPort()
{
stringstream ss;
ss << "sip:" << m_ipAddr << ":" << m_portAddr;
return ss.str(); // Now it returns something!
}
Related
So I have that simple code inside button click method:
std::stringstream ss;
unsigned counter = 0;
while(true)
{
ss.clear();
ss << DEFAULT_USER_CONFIG_NAME << " " << ++counter;
const char* name = ss.str().c_str();
MessageBox(name);
/* ... while break condition */
}
The problem is that messagebox is empty. But it works correctly when I pass text directly:
MessageBox(ss.str().c_str()); // that shows text just fine
What I found with debugger is that local variable "name" is not created(at least it is not showing in debugger). Any clue why it is working when passed directly and failing otherwise? Also when i casted "name" to CString it returned true on IsEmpty() check.
The expression ss.str() creates a temporary std::string object. Storing the result of c_str() thus points to memory of a temporary, which quickly turns into a dangling pointer. Once the full expression statement
const char* name = ss.str().c_str();
// ^ this is where the temporary ss.str() gets destroyed.
is evaluated, the temporary gets destroyed.
You already know, how to solve this, by placing the expression creating the temporary inside the full expression, that consumes it. This extends the lifetime of the temporary until the end of the full expression:
MessageBox(ss.str().c_str());
// ^ this is where the temporary ss.str() gets destroyed.
The following illustrates the sequence of events. Let's just define a few placeholder classes and functions:
void messagebox(const char*) {
cout << "messagebox()" << endl;
}
struct tmp {
tmp(const char* content) : content(content) { cout << "tmp c'tor" << endl; }
~tmp() { cout << "tmp d'tor" << endl; }
const char* c_str() { return content.c_str(); }
private:
string content;
};
struct ss {
tmp str() { return tmp("test"); }
};
With this in place, your first version
ss s;
const char* name = s.str().c_str();
messagebox(name);
produces the following output:
tmp c'tor
tmp d'tor
messagebox()
Whereas the second version
ss s;
messagebox(s.str().c_str());
changes the sequence in the output:
tmp c'tor
messagebox()
tmp d'tor
(Live sample code)
I have following code snippet to modify the stringstream such that it will have additional one char infront. But, i couldn't get the expected result.
void modifyStream(std::istream& s1)
{
if (s1.putback('Y'))
std::cout << s1.rdbuf() << '\n';
else
std::cout << "putback failed\n";
}
int main(int argc, const char * argv[])
{
const char* str = "Hello, world";
std::stringstream s1(str); // IO stream
modifyStream(s1);
return 0;
}
Output: putback failed
But, i am expecting the output of "YHello, world".
Can someone help to resolve this?
There is a misunderstanding about the putback method in your code: Its purpose is not to prepend data to the stream but to replace one already extracted character with another (you do not add anything, you replace an old character with something new). This is a bit more understandable by reading the documentation of sputbackc which is called by putback.
Example (from encppreference):
std::stringstream s1("Hello, world"); // IO stream
s1.get();
if (s1.putback('Y')) // modifies the buffer
std::cout << s1.rdbuf() << '\n';
else
std::cout << "putback failed\n";
Output:
Yello, world
The call s1.putback('Y') puts the character 'Y' back at the place of the last extracted character (in this case 'H').
I am trying to cout a const char *
This is how I convert an int to a string and concatenate it with the const char*
char tempTextResult[100];
const char * tempScore = std::to_string(6).c_str();
const char * tempText = "Score: ";
strcpy(tempTextResult, tempText);
strcat(tempTextResult, tempScore);
std::cout << tempTextResult;
The result when printing is: Score:
Does anyone know why the 6 is not printing?
Thanks in advance.
As the docs for c_str say, "The pointer returned may be invalidated by further calls to other member functions that modify the object." This includes the destructor.
const char * tempScore = std::to_string(6).c_str();
This makes tempScore point to a temporary string that no longer exists. You should do this:
std::string tempScore = std::to_string(6);
...
strcat(tempTextResult, tempScore.c_str());
Here, you're calling c_str on a string that continues to exist.
You have marked this post as C++.
One possible C++ approach: (not compiled, not tested)
std::string result; // empty string
{
std::stringstream ss;
ss << "Score: " // tempText literal
<< 6; // tempScore literal
// at this point, the values placed into tempTextResult
// are contained in ss
result = ss.str(); // because ss goes out of scope
}
// ss contents are gone
// ... many more lines of code
// ... now let us use that const char* captured via ss
std::cout << result.c_str() << std::endl;
// ^^^^^^^ - returns const char*
Consider:
std::string s_a, s_b;
std::stringstream ss_1, ss_2;
// at this stage:
// ss_1 and ss_2 have been used and are now in some strange state
// s_a and s_b contain non-white space words
ss_1.str( std::string() );
ss_1.clear();
ss_1 << s_a;
ss_1 << s_b;
// ss_1.str().c_str() is now the concatenation of s_a and s_b,
// <strike>with</strike> without space between them
ss_2.str( s_a );
ss_2.clear();
// ss_2.str().c_str() is now s_a
ss_2 << s_b; // line ***
// ss_2.str().c_str() the value of s_a is over-written by s_b
//
// Replacing line *** above with "ss_2 << ss_2.str() << " " << s_b;"
// results in ss_2 having the same content as ss_1.
Questions:
What is the difference between stringstream.str( a_value ); and
stringstream << a_value; and, specifically, why does the first not
allow concatenation via << but the second does?
Why did ss_1 automatically get white-space between s_a and s_b, but
do we need to explicitly add white space in the line that could
replace line ***: ss_2 << ss_2.str() << " " << s_b;?
The problem you're experiencing is because std::stringstream is constructed by default with ios_base::openmode mode = ios_base::in|ios_base::out which is a non-appending mode.
You're interested in the output mode here (ie: ios_base::openmode mode = ios_base::out)
std::basic_stringbuf::str(const std::basic_string<CharT, Traits, Allocator>& s) operates in two different ways, depending on the openmode:
mode & ios_base::ate == false: (ie: non-appending output streams):
str will set pptr() == pbase(), so that subsequent output will overwrite the characters copied from s
mode & ios_base::ate == true: (ie: appending output streams):
str will set pptr() == pbase() + s.size(), so that subsequent output will be appended to the last character copied from s
(Note that this appending mode is new since c++11)
More details can be found here.
If you want the appending behaviour, create your stringstream with ios_base::ate:
std::stringstream ss(std::ios_base::out | std::ios_base::ate)
Simple example app here:
#include <iostream>
#include <sstream>
void non_appending()
{
std::stringstream ss;
std::string s = "hello world";
ss.str(s);
std::cout << ss.str() << std::endl;
ss << "how are you?";
std::cout << ss.str() << std::endl;
}
void appending()
{
std::stringstream ss(std::ios_base::out | std::ios_base::ate);
std::string s = "hello world";
ss.str(s);
std::cout << ss.str() << std::endl;
ss << "how are you?";
std::cout << ss.str() << std::endl;
}
int main()
{
non_appending();
appending();
exit(0);
}
This will output in the 2 different ways as explained above:
hello world
how are you?
hello world
hello worldhow are you?
Suggest you read stringstream reference: http://en.cppreference.com/w/cpp/io/basic_stringstream
std::stringstream::str() Replaces the contents of the underlying string
operator<< Inserts data into the stream.
I have a static method that should return the next available id. Several static members in other classes call this function, so each gets a different id assigned. However, when I am printing the assigned values I dont get "id0", "id1" but just a symbol like "*". I'm using this code:
int A::i = 0; //static member
std::string A::id()
{
std::stringstream sst;
sst<< "id" << A::i;
i++;
return sst.str(); //i've tried to return a const char* too, but doesnt work either
}
//assigning id's in several classes like this:
const char* B::id = A::id().c_str();
const char* C::id = A::id().c_str();
//printing them in the main function:
std::cout << B::id << " " << C::id << "\n";
I dont understand why the code above doesnt work. When I am executing the following code the expected result "id10" is printed:
static std::string gt()
{
std::stringstream ss;
ss << "id" << 10;
return ss.str();
}
Look at
const char* C::id = A::id().c_str();
You are creating a new id string, then you take a pointer to its data (as a c-string), and inmediately after that the temporary string to which contents you are pointing gets destroyed. Simple answer: either stick to std::string or to plain int ids.