So I have my class called array and I want to return it as a formatted string, like this: [first, second, third, ..., last]. Now I wrote the method that is trying to do so:
std::string& array::to_string()
{
char buffer[1];
std::string s("[");
for (auto &x: *this)
{
if (&x == this->end()) s += _itoa_s(x, buffer, 10) + "]";
else s += _itoa_s(x, buffer, 10) + ",";
}
return s;
}
And yes, I've included <string>. Now, in the other part of my program I use std::cout << myArray.to_string() << '\n'. The error I get (during the execution) is just Visual Studio throwing me to stdlib.h header and showing this part of it:
__DEFINE_CPP_OVERLOAD_SECURE_FUNC_1_1(
_Success_(return == 0)
errno_t, _itoa_s,
_In_ int, _Value,
char, _Buffer,
_In_ int, _Radix
)
What am I doing wrong?
The string s is local to the function to_string, and its destructor runs as to_string returns, so returning and using a reference to the already-destructed string creates undefined behaviour. Return it by value instead:
std::string array::to_string() const
{
// a more robust, C++-style implementation...
std::ostringstream oss;
size_t n = 0;
for (const auto& x: *this)
oss << (n++ ? ',' : '[') << x;
oss << ']';
return oss.str();
}
You are returning a reference to a std::string that is scoped inside your array::to_string() method.
When the method exits, the local s variable is out of scope, thus it is destroyed, resulting in a "dangling reference" being returned.
You should either return the string by value:
std::string array::to_string()
or pass it as a reference parameter:
void array::to_string(std::string& result)
You are returning a reference to a local object. Because of this, you try to use an object that has been deallocated from the stack. Remove the & from the function signature to return it by value.
Related
#include <iostream>
void test(std::string &s) {
std::string p = s;
std::cout << p.length() << " " << p;
}
int main() {
std::string s = "Hello world";
test(s);
return 0;
}
So, the function test receives a reference to my string s from my main function.
My question is, what does this line do:
std::string p = s;
Does it shallow copy the reference and put it in p, thereby defeating the purpose of using a reference in the first place?
Or does it (p) just act as a reference?
It creates a copy of the value of the reference, it doesn't allow you to edit the content of s with p, to make p act as a reference and be able to edit s from p, you have to declare it as a reference:
std::string& p = s;
thereby defeating the purpose of using a reference in the first place?
Why does it defeat the purpose of reference, you have declared s as reference, isn't it? Not p. So as noted indeed it will copy the value which s contains.
What happens when I assign an object the value of a reference in C++?
You cannot assign the value of a reference, or at least you should not think in such terms. A reference is not a pointer. What happens is that you assign the value of an object, because a reference is the object, accessed via a different name.
void test(std::string &s) {
The fact that you are dealing with a reference is only really relevant at the point of declaration. All code in this function which uses s uses a std::string, not a std::string &.
My question is, what does this line do:
std::string p = s;
It assigns your std::string object to p, no more, no less. In other words, it does the same as it would in this program:
int main() {
std::string s = "Hello world";
std::string &s_with_different_name = s;
std::string p = s_with_different_name;
std::cout << p.length() << " " << p;
}
Or, even more simply, in this:
int main() {
std::string s = "Hello world";
std::string p = s;
std::cout << p.length() << " " << p;
}
I am trying to store a char* into a struct's char* field. I have tried different things but none of them worked. The problematic piece of code is shown below:
pInfo is the object of the struct PlayerInfo.
PlayerInfo *pInfo = (PlayerInfo*)malloc(sizeof(PlayerInfo));
The char* I get from GetAddress is stored in the Address field of PlayerInfo.
pInfo->Address = GetAddress(pInfo->playerId);
The GetAddress function is shown below. It converts integers to strings, stores them in a vector and returns the vector as a char* using &retChar[0].
char* GetAddress(int playerId)
{
std::string strPlayerId = std::to_string(playerId);
std::string strGroupId = std::to_string(group.GetGroupId());
std::string retAddress = strPlayerId + ":" + strGroupId + ":" + GenRandomChar();
//From -- http://stackoverflow.com/questions/347949/convert-stdstring-to-const-char-or-char
std::vector<char> retChar(retAddress.begin(), retAddress.end());
retChar.push_back('\0');
for(std::vector<char>::const_iterator i = retChar.begin(); i != retChar.end(); ++i)
std::cout << "retChar is " << *i << std::endl;
return &retChar[0];
}
When I print the contents, only garbage is printed. I tried printing the memory contents from gdb, but that also did not help.
char* address = GetAddress(pInfo->playerId);
std::cout << "address is " << *address << std::endl;
std::cout << "address is " << pInfo->Address << std::endl;
std::cout << "address is " << *(pInfo->Address) << std::endl;
The problem is, that your function scope local variable
std::vector<char> retChar;
goes out of scope and is destroyed after your function returned.
Thus using the returned pointer return &retChar[0]; is calling undefined behavior.
The better choice would be to pass the pointer where to copy the data as a reference
void GetAddress(int playerId, char*& result) {
std::vector<char> retChar;
// ...
std::copy(retChar.begin(),result);
}
and ensure result buffer is big enough to receive the copied data.
NOTE:
The above suggestion just solves the 1st level of your current problem. The probably better idea is to change your function simply to deal with std::string instead of using std::vector<char> and raw char* pointers (if your use case allows to refactor this):
Make PlayerInfo::Address member a std::string type
struct PlayerInfo {
// ...
std::string Address;
};
and define your GetAddress() function as follows
std::string GetAddress(int playerId) {
std::ostringstream result;
result << playerId << ":" group.GetGroupId() << ":" << GenRandomChar();
return result.str();
}
and use the results std::string::c_str() method if you really need a const char* value to pass it elsewhere.
I think the idea of using std::vector<char> in the selected answer to How to convert a std::string to const char* or char*? is that the std::vector<char> is your writable character array, not that you should extract a char * from it. (You can, however, copy the contents into a different memory location identified by a char *, as you have already seen.)
But I would ask why you are storing a char * in the Address member of PlayerInfo. Why don't you make that member an std::string and change the return type of getAddress() to std::string, in which case getAddress can simply return retAddress?
Alternatively, you can declare getAddress like this: void getAddress(int playerId, std::string& retAddress) and the code inside the function is even simpler, because you don't have to declare retAddress as a local variable inside the function.
#include <iostream>
#include <sstream>
template <typename T>
const char* numberToString(T number) {
std::ostringstream ss;
ss << number;
return ss.c_str();
}
int main() {
printf(numberToString(123));
return 0;
}
My error:
1>d:\programming\euler\problem 4\problem 4\problem 4\source.cpp(8): error C2039: 'c_str' : is not a member of 'std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>>'
1> d:\programming\euler\problem 4\problem 4\problem 4\source.cpp(26) : see reference to function template instantiation 'const char *numberToString<int>(T)' being compiled
1> with
1> [
1> T=int
1> ]
Why doesn't this work?
c_str is a member of std::string, not ostringstream. If you want to get a string out of the stream, use str(). Note, however, that returning a const char* from that string is wrong - the string will go out of scope before you can use the const char*. Therefore, have your function return a string (or have it get a buffer to write to):
template <typename T>
std::string numberToString(T number) {
std::ostringstream ss;
ss << number;
return ss.str();
}
c_str() does not exist for std::ostringstream. What you meant was:
template <typename T>
const char* numberToString(T number)
{
std::ostringstream ss;
ss << number;
return ss.str().c_str();
}
After you make that change, you will have another problem: you will be returning a pointer to a buffer that was just destroyed. To fix that, you should return a std::string:
template <typename T>
std::string numberToString(T number)
{
std::ostringstream ss;
ss << number;
return ss.str();
}
Which you can do with std::to_string already, so it is really pointless to write your own function.
That's because c_str() is the member function of std::string which returns a const char*.
To get the underlying string of a strinstream, you must use str().
The error was pretty much self explanatory:
error C2039: 'c_str' : is not a member of 'std::basic_ostringstream
Note however that you're returning a pointer to something (the underlying data of the temporary string returned by str()) that will not exist after the return statement (i.e. in the calling code) and that manipulating that pointer will quite sureley end up in undefined behavior.
As you are in C++, you could rather return the std::string directly, and output it with
std::cout << numberToString(123);
which would be safer.
You want to do:
template <typename T>
std::string numberToString(T number) {
std::ostringstream ss;
ss << number;
return ss.str();
}
int main() {
std::cout << numberToString(123);
return 0;
}
To get the underlying std::string in std::ostringstream, and then the resulting c-style string in std::string. As others have pointed out, the pointer returned by c_str goes out of scope, and therefore you must copy it to a buffer or to another std::string. If you insist on using printf, then use c_str on the function call:
printf("%s", numberToString(123).c_str());
For more information, see Is it a good idea to return " const char * " from a function?
Depending on what somestlstring is and what is being done there.
If it is a local variable you are returning a pointer into memory that
is being released when GetSomeString completes, so it is a dangling
pointer and an error.
It all boils down to the lifetime of somestlstring and the operations
you perform on it. The pointer returned by .c_str() is guaranteed to
be valid only up to the next mutating operation in the string. So if
something changes somestlstring from the call to .c_str() and before s
is constructed you will be in undefined behavior land.
However, you can simply use std::to_string.
std::string s = std::to_string(123);
I will start by saying I've read this topic: C++ Return reference / stack memory. But there, the question was with an std::vector<int> as object-type. But I though the behavior of std::string was different. Wasn't this class especially made for using strings without having to worry about memory-leaks and wrong usage of memory?
So, I already know this is wrong:
std::vector<t> &function()
{
vector<t> v;
return v;
}
But is this wrong as well?
std::string &function()
{
string s = "Faz";
s += "Far";
s += "Boo";
return s;
}
Thanks
Extra question (EDIT): So, am I correct when I say returning (by value) an std::string doesn't copy the char sequence, only a pointer to the char * array and an size_t for the length?
If this statement is correct, is this the valid way to create a deep copy of a string (to avoid manipulating two strings at once)?
string orig = "Baz";
string copy = string(orig);
It doesn't matter what the type is; this pattern is always completely, 100% wrong for any object type T:
T& f() {
T x;
return x;
} // x is destroyed here and the returned reference is thus unusable
If you return a reference from a function, you must ensure that the object to which it refers will still exist after the function returns. Since objects with automatic storage duration are destroyed at the end of the block in which they are declared, they are guaranteed not to exist after the function returns.
You are really close to making those functions work:
std::string function()
{
string s = "Faz";
s += "Far";
s += "Boo";
return s;
}
Simply make them return a copy instead of a reference and you're set. This is what you want, a copy of the stack-based string.
It gets better too, because the return value optimization (RVO) will only create the string once and return it, just like if you had created it on the heap and returned a reference to it, all behind the scenes!
Don't return references, return by value:
std::string function() // no ref
{
string s = "Faz";
s += "Far";
s += "Boo";
return s;
}
If your compiler can do named return value optimization, aka NRVO, (which is likely), it will transform this into something roughly equivalent to the following, which avoids any extraneous copies:
// Turn the return value into an output parameter:
void function(std::string& s)
{
s = "Faz";
s += "Far";
s += "Boo";
}
// ... and at the callsite,
// instead of:
std::string x = function();
// It does this something equivalent to this:
std::string x; // allocates x in the caller's stack frame
function(x); // passes x by reference
Regarding the extra question:
The copy constructor of string always does a deep copy. So, if there are copies involved, there are no aliasing issues. But when returning by value with NRVO, as you can see above, no copies are made.
You can make copies using several different syntaxes:
string orig = "Baz";
string copy1 = string(orig);
string copy2(orig);
string copy3 = orig;
The second and third have no semantic difference: they're both just initialization. The first one creates a temporary by calling the copy constructor explicitly, and then initializes the variable with a copy. But a compiler can do copy elision here (and it's very likely that it will) and will make only one copy.
The problem with this (regardless of the type) is that you're returning a reference to memory that goes out of scope oncee the return is hit.
std::string &function()
{
string s = "Faz";
s += "Far";
s += "Boo";
// s is about to go out scope here and therefore the caller cannot access it
return s;
}
You would want to change the return type to not be reference but by value, therefore a copy of s gets returned.
std::string function()
{
string s = "Faz";
s += "Far";
s += "Boo";
// copy of s is returned to caller, which is good
return s;
}
You can take the address of the returned string and compare it with the address of the original string, as shown below:
#include <iostream>
using namespace std;
string f() {
string orig = "Baz";
string copy1 = string(orig);
string copy2(orig);
string copy3 = orig;
cout << "orig addr: " << &orig << endl;
cout << "copy1 addr: " << ©1 << endl;
cout << "copy2 addr: " << ©2 << endl;
cout << "copy3 addr: " << ©3 << endl;
return orig;
}
int main() {
string ret = f();
cout << "ret addr: " << &ret << endl;
}
I got the following:
orig addr: 0x7ffccb085230
copy1 addr: 0x7ffccb0851a0
copy2 addr: 0x7ffccb0851c0
copy3 addr: 0x7ffccb0851e0
ret addr: 0x7ffccb085230
You see orig and ret point to the same string instance in memory, so orig is returned by reference. copy1, copy2, copy3 are copies of orig because they point to different objects in memory.
In C++ what is the best way to return a function local std::string variable from the function?
std::string MyFunc()
{
std::string mystring("test");
return mystring;
}
std::string ret = MyFunc(); // ret has no value because mystring has already gone out of scope...???
No. That is not true. Even if mystring has gone out of scope and is destroyed, ret has a copy of mystring as the function MyFunc returns by value.
There will be a problem if your code is like:
std::string& MyFunc()
{
std::string mystring("test");
return mystring;
}
So, the way you've written it is OK. Just one advice - if you can construct the string like this, I mean - you can do it in one row, it's sometimes better to do it like this:
std::string MyFunc()
{
return "test";
}
Or if it's more "complicated", for example:
std::string MyFunct( const std::string& s1,
const std::string& s2,
const char* szOtherString )
{
return std::string( "test1" ) + s1 + std::string( szOtherString ) + s2;
}
This will give a hint to your compiler to do more optimization, so it could do one less copy of your string (RVO).
None of the previous answers contained the key notion here. That notion is move semantics. The std::string class has the move constructor, which means it has move semantics. Move semantics imply that the object is not copied to a different location on function return, thus, providing faster function execution time.
Try to step debug into a function that returns std::string and examine the innards of that object that is about to be return. You shall see a member field pointer address xxx. And then, examine the std::string variable that received the function's return value. You shall see the same pointer address xxx in that object.
This means, no copying has occurred, ladies and gentlemen. This is the move semantics, God bless America!
As mentioned, the std::string is copied. So even the original local variable has gone out of scope, the caller gets a copy of the std::string.
I think reading on RVO can totally clear your confusion. In this case, it's accurately referred to as NRVO (Named RVO) but the spirit is the same.
Bonus reading: The problem with using RVO is that it's not the most flexible thing in the world. One of the big buzzes of C++0x is rvalue references which intends to solve that problem.
Have you tried it?
The string is copied when it's returned.
Well that's the official line, actually the copy is probably optimised away, but either way it's safe to use.
Well, ret will have a value of mystring after MyFunc(). In case of returning the result by value a temporary object is constructed by copying the local one.
As for me, there are some interesting details about the topic in these sections of C++ FAQ Lite.
It depends on the use case. If an instance should keep responsibility for a string, strings should be returned by a const reference. The problem is, what to do, if there isn't any object to return. With pointers, the invalid object could be signaled using 0. Such a "null-object" could be also used with references (e.g., NullString in the code snippet).
Of course, a better way to signal an invalid return value is throwing exceptions.
Another use case is if the responsibility for the string is transferred to the caller. In this case auto_ptr should be used. The code below shows all this use cases.
#include <string>
#include <memory> //auto_ptr
#include <iostream>
using std::string;
using std::auto_ptr;
using std::cout;
using std::endl;
static const string NullString("NullString\0");
///// Use-Case: GETTER //////////////////
//assume, string should be found in a list
// and returned by const reference
//Variant 1: Pseudo null object
const string & getString( bool exists ) {
//string found in list
if( exists ) {
static const string str("String from list");
return str;
}
//string is NOT found in list
return NullString;
}
//Variant 2: exception
const string & getStringEx( bool available ) {
//string found in list
if( available ) {
static const string str("String from list");
return str;
}
throw 0; //no valid value to return
}
///// Use-Case: CREATER /////////////////
auto_ptr<string> createString( bool ok )
{
if( ok ){
return auto_ptr<string>(new string("A piece of big text"));
}else{
return auto_ptr<string>();
}
}
int main(){
bool ok=true, fail=false;
string str;
str = getString( ok );
cout << str << ", IsNull:"<<( str == NullString )<<endl;
str = getString( fail );
cout << str << ", IsNull:"<<( str == NullString )<<endl;
try{
str = getStringEx( ok );
cout << str <<endl;
str = getStringEx( fail );
cout << str <<endl; //line won't be reached because of ex.
}
catch (...)
{
cout << "EX: no valid value to return available\n";
}
auto_ptr<string> ptext = createString( ok );
if ( ptext.get() ){
cout << *ptext << endl;
} else {
cout << " Error, no text available" << endl;
}
ptext = createString( fail );
if ( ptext.get() ){
cout << *ptext << endl;
} else {
cout << " Error, no text available"<<endl;
}
return 0;
}