3

Given this minimal example.

#include <iostream>
#include <string>

void print_ptr(const std::string& s)
{
    const char* data = s.data();
    std::cout << "ptr: " << (void*)data << std::endl;
}

std::string str_return(const char* suffix)
{
    std::string s("prefix");
    s += " ";
    s += suffix;
    print_ptr(s);
    return s;
}

int main()
{
    std::string s = str_return("suffix"), t;
    print_ptr(s);
    t = str_return("suffix2");
    print_ptr(t);
    return 0;
}

I compiled like this:

g++ -std=c++98 -fno-elide-constructors -g -Wall  str_return.cpp -o str_return

My g++:

gcc version 4.7.1

The output:

ptr: 0x804b04c
ptr: 0x804b04c
ptr: 0x804b07c
ptr: 0x804b07c

Why are the pointers still equal?

  • It should not be return value optimization - I switched it off
  • It should not be move constructors since I took a really old standard of c++

How can I disable this behaviour?

5
  • 1
    Is there any reason to do that? Commented Nov 6, 2013 at 8:33
  • @JurajBlaho I just want to be sure what's the reason for it's not a copy. That way, I know what is necessary for a fast string return. Commented Nov 6, 2013 at 8:35
  • Just FYI: when compiled using clang (3.2) with the gcc libstdc++, I get a segmentation fault upon the return from str_return(). This strongly hints at a bug/non-standard behaviour of the library. When using the llvm libc++, the pointers are different (though it reuses s.data() in t, i.e. the 1st and 3rd line report the same ptr). Commented Nov 6, 2013 at 8:42
  • @Walter, that means your clang installation is borked, not that there's a bug in libstdc++. libstdc++ uses Copy-On-Write for its std::string which is 100% conforming in C++03 (which this example uses) Commented Nov 6, 2013 at 9:25
  • If you want to prevent Copy-On-Write sharing of the buffer copy the buffer explicitly: std::string copy(s.data(), s.size()), but in this example that's just a harmful pessimisation, because after str_return returns s and t are not sharing their data with another object anyway. Commented Nov 6, 2013 at 9:30

3 Answers 3

6

Return value optimization affects the local object (s in your str_return function). You never instrument that.

The string object itself manages dynamic memory and chooses to hand that managed memory over to the next string upon return. What you're instrumenting is that managed memory. Sensibly enough, that doesn't change.

If you really want to see the effect of RVO, instrument the local object:

#include <iostream>
#include <string>

void print_ptr(const std::string& s)
{
    std::cout << "ptr: " << static_cast<const void *>(&s) << std::endl;
}

std::string str_return(const char* suffix)
{
    std::string s("prefix");
    s += " ";
    s += suffix;
    print_ptr(s);
    return s;
}

int main()
{
    std::string s = str_return("suffix");
    print_ptr(s);
    std::string t = str_return("suffix2");
    print_ptr(t);
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, I get what you mean from the example. So you think that there is nothing that will make my compiler do a hard copy of the internal data?
@Johannes: You can force a copy of the object if you like.
Ok, but this code, unchanged, will probably always be safe of hard copies (no matter what compiler flags I'll use)?
@Johannes: It will in C++11. It's unspecified in C++98/03.
What does "be safe of hard copies" mean?
1

You may not be experiencing RVO. The observed behavior may be caused by the copy on write optimization used in the implementation of std::string in GCC. Therefore a copy constructor may actually run, but the allocated buffer is not copied.

2 Comments

It's not "non-standard" in C++98, and in C++11 there are move semantics which produce the same behaviour.
@KerrekSB See my comment to the original Q.
0

I cant comment answers, so I will put my notice here: If you put constructor call for you string s, and after that you call str_return - addresses will be different:

std::string s; // implicit constructor call
print_ptr( s );
s  = str_return( "suffix" );
print_ptr( s );
std::cout << std::endl;

the output will be:

ptr: 0x28fec4  // for the original s;
ptr: 0x28fec8  // for local variable in function str_return
ptr: 0x28fec4  // the address of s after call str_return didn't change

5 Comments

That isn't helpful, the objects don't contain the same data in your example.
Didn't get you. Which objects have to contain the same data?
The default constructed string doesn't contain the same data as the one returned by str_return. In any case, you apparently didn't test with GCC or another implementation that use COW strings, because the address of the string held by s does change if you use COW strings. All you've done is show that another implementation behaves differently to GCC, which doesn't help the OP who is using GCC.
After assigning s = str_return( "suffix" ); s will be "prefix suffix". And it was compiled by g++. And if you look closer, after assigning the result of the function str_return to the string s, its address still same: 0x28fec4, like after calling constructor.
What are you printing out, the address of the string object, or its data? Because with G++ the data will change after assignment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.