Passing a string by value, reference and rvalue - c++

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;
}

Related

C++ MFC missing const char* variable

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)

how to return object without create copy of that?

I develop simple c++ class to testing when c++ objects destroy; now I have a problem, when an object return by function, c++ create a new object and return that and when return reference destroy object what is my mistake ?
simple class attached below.
#include <iostream>
using namespace std;
static int freeCounter=0;
class TestCopy {
private:
string pStr;
public:
TestCopy(const TestCopy &obj){
pStr=obj.pStr;
}
TestCopy(string &test){
pStr=test;
}
~TestCopy(){ freeCounter++; cout << freeCounter <<"\t" << pStr << endl; }
TestCopy get(){
TestCopy x=*this;
return TestCopy(x); // -> TestCopy(x) is first destroy in result
}
string getStr(){
return pStr;
}
};
int main(){
string xstr="test";
TestCopy x(xstr); // x is third destroy
TestCopy x2=x.get(); // x2 is second destroy
cout << x.getStr() << endl;
return 0;
}
and result
1 test
test
2 test
3 test
x in function get is a local object, when the function finishes, x will be destroyed.
so, x is the first destroyed.
First a review of OP's code. I've modified it slightly to make what's going on more obvious.
#include <iostream>
using namespace std;
static int allocCounter = 0;
class TestCopy
{
private:
string pStr;
int counter;
public:
TestCopy(const TestCopy &obj)
{
allocCounter++;
counter = allocCounter;
cout << "copy construct " << counter << endl;
pStr = obj.pStr;
}
TestCopy(const string &test)
{
allocCounter++;
counter = allocCounter;
cout << "string construct " << counter << endl;
pStr = test;
}
~TestCopy()
{
cout << counter << "\t" << pStr << endl;
}
TestCopy get()
{
TestCopy x = *this; // copy constructed
return TestCopy(x); // copy constructed and copy elision
}
string getStr()
{
return pStr;
}
TestCopy & operator=(const TestCopy &obj)
{
cout << "assigned " << obj.counter << " to "<< counter << endl;
pStr = obj.pStr;
// counter = obj.counter; deliberately left out
return *this;
}
};
int main()
{
string xstr = "test";
TestCopy x(xstr); // string constructed
TestCopy x2 = x.get(); // Would be a copy constructed if not for copy elision
return 0;
}
Output
string construct 1
copy construct 2
copy construct 3
2 test
3 test
1 test
Note no calls to the assignment operator even with TestCopy x=*this;
Alright. Now how do we chop some of this down?
First we get rid of a redundant copy in get
TestCopy get()
{
return *this; // copy constructed. Or is it? The copy construction could
// happen at the caller. Either way it is copied and elided
}
Output
string construct 1
copy construct 2
2 test
1 test
So at this point we know there is no need to copy or assign in get because the return statement will do it for us. This is the important part with respect to OP's question.
But if we change main a bit and add an assignment operator we can observe a bit more interesting behaviour.
int main()
{
string xstr = "test";
TestCopy x(xstr); // string constructed
TestCopy x2(""); //string constructed
x2 = x.get(); // assigned and a copy construct when returning from get
cout << "done main" << endl;
return 0;
}
Output
string construct 1
string construct 2
copy construct 3
assigned 3 to 2
3 test
done main
2 test
1 test
The return from get was assigned to x2, then destroyed. x2 gets destroyed and finally x.
thank you #seaman with your help I found my mistake.
by changing
TestCopy x=*this;
with
const TestCopy &x=*this;
problem solved

Reference Parameters Address Automatically NOT passed

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

Logger logs 2 times instead of one time because of copy

I am writing my own Logger. I know there are alot out there but i would like to write it myself. It has messages which get logged when they are leaving the scope. So if i call Logger::Error(__FILE__,__LINE__) << "some error" it gets logged directly since there is no assignemnt to a variable.
But i would like to have a message which logs the time of the scope. So it mesures the time since creation and since delete. Therefore i need it to be assigned to a variable in the scope with for example this marko: #define LOG_SCOPE_TIME LogTimer ___t = Logger::Timer(__FILE__,__LINE__)
It can be used like this:
int main()
{
{
LOG_SCOPE_TIME << "Some scope";
//do something to mesure
}
}
Example output:
[timer][File:main.cpp][Line:19][thread:8024][21-05-2015][13:15:11] Some scope[0µs]
[timer][File:main.cpp][Line:19][thread:8788][21-05-2015][13:15:11] Some scope[118879µs]
But this actually causes 2 logs. The first of the temporary created LogTime object (with time 0µs) and the second with the real scope time.
How do i prevent from this? Any suggestions? Here is a reduced example:
#include <iostream>
#include <chrono>
class LogTimer {
std::string str;
std::chrono::high_resolution_clock::time_point m_start;
public:
LogTimer(const std::string& file, int i)
: m_start(std::chrono::high_resolution_clock::now())
{
str = file + ':' + std::to_string(i);
}
~LogTimer() {
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>
(end - m_start).count();
std::cout << str << " [" << duration << "µs]\n";
}
LogTimer& operator<<(const std::string& p) {
str += '[' + p + ']';
return *this;
}
};
namespace Logger {
LogTimer Timer(const std::string& f, int i) {
return LogTimer(f, i);
}
}
#define LOG_SCOPE_TIME LogTimer ___t = Logger::Timer(__FILE__,__LINE__)
int main()
{
LOG_SCOPE_TIME << "something"; // logs two lines
}
You're running into an operator precedence issue, sort of. When you use your macro:
LOG_SCOPE_TIME << "Some scope";
That expands into:
LogTimer ___t = Logger::Timer(__FILE__,__LINE__) << "Some scope";
Which gets evaluated as:
LogTimer ___t = (Logger::Timer(__FILE__,__LINE__) << "Some scope");
since << has higher precedence than =. As such, you are preventing copy elision from happening since the compiler has to now create a temporary Timer to perform the << "Some Scope" and then copy it into ___t (which is technically a reserved name). The additional copy means an addition destructor, which in your case means an extra line logged.
You need to ensure copy elision. The simplest way I can think of is to change your macro to do:
#define LOG_SCOPE_TIME LogTimer ___t = Logger::Timer(__FILE__,__LINE__); ___t
That way, your original example expands to:
LogTimer ___t = Logger::Timer(__FILE__,__LINE__); ___t << "Some scope";
No issues there.

Issue with stringstream data getting corrupt.

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!
}