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)
Related
I'm just comparing the performance of passing a string to a function. The benchmark results are interesting.
Here's my code:
void add(std::string msg)
{
msg += "world";
}
void addRvalue(std::string&& msg)
{
msg += "world";
}
void addRef(std::string& msg)
{
msg += "world";
}
void StringCreation() {
add(std::string("hello "));
}
void StringCopy() {
std::string msg("hello ");
add(msg);
}
void StringMove() {
std::string msg("hello ");
add(std::move(msg));
}
void StringRvalue() {
std::string msg("hello ");
addRvalue(std::move(msg));
}
void StringReference() {
std::string msg("hello ");
addRef(msg);
}
StringCreation(), StringRvalue() and StringReference() are equivalent. I'm surprised StringMove() is the least performant - worse than pass by value which involves a copy.
Am I right in thinking that calling StringMove() involves one move constructor followed by a copy constructor when it calls add()? It doesn't just involve one move constructor? I thought move construction was cheap for a string.
Update
I increased the length of the string passed to add() and that did make a difference. Now StringMove() is only 1.1 times slower than StringCreation and StringReference. StringCopy is now the worst, which is what I expected.
Here are the new benchmark results.
So StringMove doesn't involve copying after all - only for small strings.
Let's analyze your code and suppose long strings (without applied SSO):
void add(std::string msg) {
msg += "world";
}
void StringCreation() {
add(std::string("hello "));
}
Here, a converting constructor (ConvC) from the string literal is called first to initialize the temporary std::string("hello "). This temporary (an rvalue) is then used to initialize the parameter msg by the move constructor (MC). However, the latter is very likely optimized away by copy elision. Finally, the operator += is called. Bottom line: 1x ConvC and 1x +=.
void StringCopy() {
std::string msg("hello ");
add(msg);
}
Here, the parameter msg is copy-initialized (by copy constructor - CC) by the lvalue argument msg. Bottom line: 1x ConvC, 1x CC, and 1x +=. In case of long strings, this is the slowest version, since copy involves dynamic memory allocations (the only case).
void StringMove() {
std::string msg("hello ");
add(std::move(msg));
}
Why is this slower than StringCreation? Simply because there is an additional MC involved that initializes the parameter msg. It cannot be elided, since the object msg still exist after the call of add. Just it is moved-from. Bottom line: 1x ConvC, 1x MC, 1x +=.
void addRef(std::string& msg) {
msg += "world";
}
void StringReference() {
std::string msg("hello ");
addRef(msg);
}
Here, the operator += is applied to the referenced object, so there is no reason for any copy/move. Bottom line: 1x ConvC, 1x +=. Same time as for StringCreation.
void addRvalue(std::string&& msg) {
msg += "world";
}
void StringRvalue() {
std::string msg("hello ");
addRvalue(std::move(msg));
}
With Clang, the time is same as for StringReference. With GCC, the time is same as for StringMove. In fact, I don't have an explanation for this behavior for now. (It seems to me that GCC is creating some additional temporary initialized by MC. However, I don't know why.)
In this example, none of the functions that are being "benchmarked" are actually doing anything of consequence. That is, none of them actually returns an computed value that is then used elsewhere.
So, any (half-)decent compiler would probably just decide to ignore them completely!
In order for a valid benchmark to be made, then the string results from each/every call must be used for something, even simple output to a file/console.
Try this code to see what's (not) happening:
#include<iostream>
#include<string>
using namespace std;
void add(std::string msg)
{
msg += " + 'add'";
}
void addRef(std::string& msg)
{
msg += " + 'addRef'";
}
void addRvalue(std::string&& msg)
{
msg += " + 'addRefRef'";
}
int main()
{
std::string msg("Initial string!");
cout << msg << endl;
add(msg);
cout << msg << endl; // msg will be the same as before!
addRef(msg);
cout << msg << endl; // msg will be extended!
addRvalue(std::move(msg));
cout << msg << endl; // msg will again be extended
add(std::move(msg));
cout << msg << endl; // msg will be completely emptied!
return 0;
}
In C++ string literals "Hello" are const and are immutable. I wanted to make a custom string class whose strings are not const chars, so they can be changeable
Here is a snippet of code that might illustrate what I'm trying to do:
#include <iostream>
class String {
public:
char * p_start;
String(char * strSourc) // Constructor
{
p_start = strSourc;
}
};
int main()
{
String myString("Hello");
// Create object myString, send "Hello" string literal as argument
std::cout << myString.p_start << std::endl;
// Prints "Hello"
*myString.p_start = 'Y';
// Attempt to change value at first byte of myString.p_start
std::cout << myString.p_start << std::endl;
// Prints "Hello" (no change)
myString.p_start = "Yellow";
// Assigning a string literal to p_start pointer
std::cout << myString.p_start << std::endl;
// Prints Yellow, change works. I thought myString "Hello" was const chars, immutable
return 0;
}
So, I'm confused. I've looked everywhere and it says that string literals, like "Hello", are immutable, each of their char bytes are unchangeable. Though I managed to assign Yellow to the p_start pointer, changing the first letter. Though changing the single letter H to a Y through dereferencing the H pointer didn't do anything.
Any insights would help me, thanks.
I think you're confusing about pointer and pointee.
p_start = "Yellow", you're changing the value of pointer, to point to "Yellow". *p_start = 'Y', you're changing the value of pointee, the content p_start points to, not itself. As you said, "Yellow" are const chars, so the behaviour try to modify them is UB.
You can make a copy of it in the ctor, then you can modify the chars, which are managed by the class. Yes, it will be a new copy, but it won't be a waste of memory. And you have no choice if you want them to be changable.
not sure if anyone finds this helpful after so long but since I am learning myself I took your above code and made it work by copying. It now has a member variable for size and cleans up using delete when you assign a new string literal to it (const char*).
#include <iostream>
class String {
public:
char * p_start;
int m_size;
String(const char * strSourc) // Constructor
{
//The following will get the size of the parameter.
int SizeParameter=0;
while (*(strSourc+SizeParameter) != '\0')
{
SizeParameter++;
}
// size of string saved.
m_size = SizeParameter;
// allocate enough memory so we can copy strSourc
p_start = new char[SizeParameter+1];
//copy the contents strSourc
for(int i=0; i<SizeParameter+1; i++)
{
*(p_start+i) = *(strSourc+i);
}
}
//Handle change of string value.
char* AssignNewString (const char* newtext)
{
//clean
delete p_start;
int SizeParameter=0;
while (*(newtext+SizeParameter) != '\0')
{
SizeParameter++;
}
// size of string saved.
m_size = SizeParameter;
// allocate enough memory so we can copy strSourc
p_start = new char[SizeParameter+1];
//copy the contents strSourc
for(int i=0; i<SizeParameter+1; i++)
{
*(p_start+i) = *(newtext+i);
}
return p_start;
}
char* operator=(const char* newtext)
{
AssignNewString(newtext);
}
};
int main()
{
String myString("Hello");
// Create object myString, send "Hello" string literal as argument
std::cout << "string size: " << myString.m_size << std::endl;
std::cout << myString.p_start << std::endl;
// Prints "Hello"
*myString.p_start = 'Y';
// Attempt to change value at first byte of myString.p_start
std::cout << myString.p_start << std::endl;
// Prints "Hello" (no change)
myString = "yellow";
// Assigning a string literal to p_start pointer
myString = "THIS IS A LONGER STRING";
std::cout << myString.p_start << std::endl;
std::cout << "string size: " << myString.m_size << std::endl;
return 0;
}
Note I am learning myself so do let me know if I am doing something wrong. But so far, it seems to work.
I have the following issue with reference parameters:
When we have a function with reference parameters, the compiler will automatically pass to that function, the address of any argument it is called with.
Example (with object):
class sample {
char *s;
public:
sample(); // normal constructor
sample(const sample &ob); // copy constructor
~sample( ) { if(s) delete [] s; cout << "Freeing s\n"; }
void show() { cout << s << "\n"; }
void set(char *str);
};// Definition will be excluded from here`
and we have a function with reference parameters of this class instance,
like:
void funtionWithRef(sample &kk); // declaration
void funtionWithRef(sample &sam){ // definition
sam.show();
}
and one function with return object of type sample:
sample functionReturnSample(); //declaration
sample functionReturnSample(){ // definition
sample sam;
sam.set("test sample");
return sam;
}
Now, when we do:
int main() {
sample temp = functionReturnSample();
funtionWithRef(temp);
return 0;
}
It works perfect. When we put temp object as an argument to funtionWithRef, compiler pass address of that object to the function.
But WHY it does not work, if we do NOT first assign a returning value of functionReturnSample to the instance, but directly put that method as an argument like :
funtionWithRef(functionReturnSample());
Why is this different, when we are doing the same thing, and according to some books I consulted, whit SHOULD
EDIT
#user657267
This is the full example (source book: C++ From Ground Up, 3rd Edition, page 219-320):
class sample {
char *s;
public:
sample(); // normal constructor
sample(const sample &ob); // copy constructor
~sample( ) { cout << "s: " << s <<" ,Freeing s\n"; if(s) delete [] s;}
void show() { cout << s << "\n"; }
void set(char *str);
sample operator=(sample &ob); // overload assignment
};
// Normal constructor.
sample::sample() {
s = new char('\0'); // s points to a null string.
cout << "Normal constructor: s: " << strlen(s) << endl;
}
// Copy constructor.
sample::sample(const sample &ob) {
cout << "Copy constructor: ob.s: "<< ob.s << " ,strlen(ob.s): " << strlen(ob.s) << "\n";
s = new char[strlen(ob.s)+1];
strcpy(s, ob.s);
}
// Load a string.
void sample::set(char *str) {
s = new char[strlen(str)+1];
strcpy(s, str);
}
// Overload assignment operator.
sample sample::operator=(sample &ob) {
/* If the target memory is not large enough
then allocate new memory. */
cout << "operator= strlen(ob.s): " << strlen(ob.s) << " ,strlen(s): " << strlen(s) << endl;
if(strlen(ob.s) > strlen(s)) {
cout << "operator= Larger memory of target object. Deleting current...\n";
delete [] s;
s = new char[strlen(ob.s)+1];
}
strcpy(s, ob.s);
return *this;
}
// Return an object of type sample.
sample input() {
char instr[80];
static sample str;
cout << "Enter a string: ";
cin >> instr;
str.set(instr);
return str;
}
int main() {
sample ob;
// assign returned object to ob
ob=input(); // This is now OK
ob.show();
return 0;
}
This wont compile, and reports error:
**error: no match for ‘operator=’ (operand types are ‘sample’ and ‘sample’)**
So it is copy/past of the code from the mentioned book. You can check please.
However I figureout if I specify overloaded = operator arguments to be const like:
sample operator=(const sample &ob); // overload assignment
Then it DOES work.
However, what is bothering me is, now when I have runnable code, I do not get why TWO times copy constructor is called.
I know it is called when input() function returns, and create temporary object, but I do not get why second time since, as much as I know (but maybe I am wrong) copy constructors are NOT called for assignment operations (same Book, pages 291-292), but it looks like, despite of that, when return *this; is called (when overloaded operator returns value), copy constructor is called?
So what is about that ?
Thankx
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!
}
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.