Why can this code run successfully in Code::block. The IDB just reports
warning: "reference to local variable ‘tmp’ returned",
but ouput the result "hello world" successfully.
#include <iostream>
#include<string>
using namespace std;
const string &getString(const string &s)
{
string tmp = s;
return tmp;
}
int main()
{
string a;
cout<<getString("hello world")<<endl;
return 0;
}
Upon leaving a function, all local variables are destroyed. By returning a reference to tmp, you are returning a reference to an object that soon ceases to exist (that is, technically, the address of a memory region whose contents are no longer meaningful).
Accessing such a dangling reference invokes what is called 'undefined behaviour' - and sadly, 'work as usual' is one kind of 'undefined behaviour'. What might happen here is that std::string keeps a small static buffer for small strings (as opposed to large strings, for which it grabs memory from the heap), and upon leaving getString the stack space occupied by this string is not zeroed so it still seems to work.
If you try a debug build, or invoke another function in between (which will effectively overwrite the stack space), it won't work anymore.
You are causing an undefined behaviour. The standard doesn't tell what happens in that case, however your compiler detected it.
tmp disappears the moment you return from getString. Using the returned reference is undefined behaviour, so anything can happen.
To fix your code, return the string by value:
string getString(const string &s)
{
...
Are you sure? It should segfault (it will with gcc on most platforms). That code does contain an error, and if you get 'lucky' and it works, then you're brushing a nasty bug under the carpet.
Your string is returned by reference, that is, rather than making a new string which is valid in the context you are returning into, a pointer to a stale, destructed, object is being returned, which is bad. const string getString... will do as the declaration for the function's return type.
The temporary object is deallocated, however its contents are still there on the stack, until something rewrites it. Try to call a few functions between calling your function and printing out the returned object:
const string& garbage = getString("Hello World!");
callSomeFunctionThatUsesALotOfStackMemory();
cout<< garbage << endl;
As you can see the below example code is just slightly modified by calling goodByeString(). Like the other answers already pointed out the variable in getString called tmp is local. the variable gets out of scope as soon as the function returns. since it is stack allocated the memory is still valid when the function returns, but as soon as the stack grows again this portion of memory where tmp resided gets rewritten with something else. Then the reference to a contains garbage.
However if you decide to output b since it isn't returned by reference the contents is still valid.
#include <iostream>
#include<string>
using namespace std;
const string &getString(const string &s)
{
string tmp = s;
return tmp;
}
string goodByeString(const string &s)
{
string tmp = "lala";
tmp += s;
return tmp;
}
int main()
{
const string &a = getString("Hello World!\n");
string b = goodByeString("ciao\n");
cout << a << endl;
return 0;
}
Related
Currently I am learning C++ with 6th edition C++ Primer Plus by Steven Prata and on p. 389 I found smth very interesting that I would like to clarify for myself.
If we have some function like this:
const std::string &ft_add_on_sides(std::string s1, std::string s2)
{
std::string res;
res = s2 + s1 + s2;
return (s2);
}
int main(void)
{
std::string input = "Hello"
std::string result = ft_add_on_sides(input, "###");
return (0);
}
As far as I understand, this function is expecting two string objects which will be copies of those, which programmer will actually pass. And this function will return const reference to some memory address.
But I am interested in return statement:
As s1 or s2 are located in a temporary storage, we can gain access to them, but when will they be destroyed? Won't I get into troubles with such return statement?
Add. Cause the variable can be destroyed and I am still asking for its address.
Parameters of a function are destroyed as soon as the return statement has executed, before the calling function continues. That means you can still use these parameters inside the return value expression, but you'd better return a copy of them.
What you wrote in your example is Undefined Behavior. Anything can happen. Typically, in debug modes compilers are reasonably good in catching accesses to destroyed strings, but in release builds the compiler no longer introduces code to catch bugs.
You can read the accepted answer here.
Return value of function
the return value is copied out of a local variable into the return register if necessary.
The functions' stack frame is no longer needed, the local variables are popped off and will not be accessible once the function returns, but s2 will be copied into the return register.
I was trying to brush up my c++ skills.
I got 2 functions:
concat_HeapVal() returns the output heap variable by value
concat_HeapRef() returns the output heap variable by reference
When main() runs it will be on stack,s1 and s2 will be on stack,
I pass the value by ref only and in each of the below functions, I create a variable on heap and concat them.
When concat_HeapVal() is called it returns me the correct output.
When concat_HeapRef() is called it returns me some memory address (wrong output). Why?
I use new operator in both the functions. Hence it allocates on heap.
So when I return by reference, heap will still be VALID even when my main() stack memory goes out of scope.
So it's left to OS to cleanup the memory. Right?
string& concat_HeapRef(const string& s1, const string& s2)
{
string *temp = new string();
temp->append(s1);
temp->append(s2);
return *temp;
}
string* concat_HeapVal(const string& s1, const string& s2)
{
string *temp = new string();
temp->append(s1);
temp->append(s2);
return temp;
}
int main()
{
string s1,s2;
string heapOPRef;
string *heapOPVal;
cout<<"String Conact Experimentations\n";
cout<<"Enter s-1 : ";
cin>>s1;
cout<<"Enter s-2 : ";
cin>>s2;
heapOPRef = concat_HeapRef(s1,s2);
heapOPVal = concat_HeapVal(s1,s2);
cout<<heapOPRef<<" "<<heapOPVal<<" "<<endl;
return -9;
}
Both your functions are legal and fine, apart from that you're later leaking the free store objects from both functions.
The first function returns a reference to the value on the free store, which is copied into your local variable in main.
The second function returns a pointer to the instance on the free store, which is stored into a pointer variable in main.
Your problem is in that you do not print the second string, you print the address of it, thanks to that there's an operator<< that prints the address a pointer contains as a number.
If you intend to access the contents of the second variable, you should dereference it when using it.
When you return by reference, you signify (among other things) that the caller does not become owner of the data and is not responsible for freeing it.
You've allocated new block and the only remaining reference to it is the one you returned. So it cannot be by reference.
But it does not apply to all heap-allocated blocks. If you have heap-allocated block to which you hold pointer in member variable to be released later e.g. in destructor, you may and often will return it by reference.
But really, pointer to std::string is a code smell. std::string should most of the time should be returned by value. That is as string, string * is by pointer, not by value.
So it's left to OS to cleanup the memory. Right?
Right.
You leak the memory.
Your OS will have to reclaim the memory itself when your process ends, or it'll remain allocated until power down.
Please don't do this.
Stop using new immediately: just create a friendly new std::string object and return it. Let the compiler's optimisations and/or move semantics sort everything out.
I'm trying to get segment fault, but I can't get it and I wonder why.
#include <iostream>
using namespace std;
class A{
public:
char *field_;
A(char *field):field_(field) {
// I believe(suppose) that it's equal to
// field_ = field;
// so actual initial string wasn't copied, only a pointer to it
}
void show() {
cout<<field_<<"\n";
}
};
int main(){
A *obj;
{
char *line="I should be freed";
obj = new (nothrow) A(line);
}
// After exiting from the previous scope,
// char *line variable should be freed.
// Constructor of class A didn't make byte for byte
//copying, so we cannot have
// access to it for sure
for(int i=0;i<4;i++) // trying to clear stack and erase char *line variable
char something[10000];
obj->show(); // and it works correctly!!!! why?
delete obj;
return 0;
}
Ok, as I understand it works correctly only because that string wasn't freed from memory.
I.e. we are just lucky.
And here we have undefined behaviour. Am I right?
Thank you in advance!!
You won't get a segmentation fault because there are no invalid memory references made by your program. I'd guess you think that ""I should be freed" is created on stack and then destroyed or freed somehow, and that is a wrong assumption because that is a constant string literal and it is placed into program data segment and is "alive" for the life of your program.
And even if it was allocated dynamically and freed automatically upon leaving the scope, you still cannot expect your program to receive SIGSEGV in that case. Because undefined behavior does not always result in segmentation faults.
Also, try to never write char *data = "blah-blah";. String literals are assumed to always be constant and trying to modify them is undefined behavior. Though people still hack around this sometimes.
char *line = "I should be freed";
You still see the content because the string literals has static storage duration. Here the string literal I should be freed resides in read only location and is freed once the program execution completes.
The program has no undefined behavior.
Where does the pointer returned by calling string::c_str() point to ? In the following code snippet, I thought I will give get a segmentation fault but it gives me the correct output. If the pointer returned by string::c_str() points to an internal location inside the string object, then when the function returns and the object destructor gets invoked, I should get an invalid memory access.
#include <iostream>
#include <string>
using namespace std;
const char* func()
{
string str("test");
return str.c_str();
}
int main()
{
const char* p = func();
cout << p << endl;
return 0;
}
Output: test
Compiler: g++ 4.3.3
Platform: ubuntu 2.6.28-19
Where does the pointer returned by calling string::c_str() point to?
It points to some place in memory where a null-terminated string containing the contents of the std::string is located.
The pointer is only valid until the std::string is modified or destroyed. It is also potentially invalidated if you call c_str() or data() again.
Basically, your safest bet is to assume the pointer obtained from c_str() is invalidated the next time you do something to the std::string object.
I should get an invalid memory access.
No, you get undefined behavior. You might get a memory access error of some kind (like a segmentation fault), but your program also might appear to continue running correctly. It might appear to work one time you run your program but fail the next.
What would you expect this to print out?
#include <iostream>
#include <string>
int main()
{
int* test = new int[20];
test[15] = 5;
std::cout << test[15] << "\n";
delete[] test;
std::cout << test[15] << "\n";
return 0;
}
In release mode on VS 2010, I get this result:
5
5
Deallocated memory doesn't necessarily throw an exception when you try to access it. The value doesn't necessarily get re-written, either. (Interestingly enough, if I change the compile to debug mode, the compiler overwrites the value with -572662307).
What happens when you try to access it is undefined by the standard. That means the compiler can do whatever it feels like doing, or choose to do nothing. (Or crash your program, or blow up the universe...)
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 6 years ago.
Consider the following code where I am returning double& and a string&. It works fine in the case of a double but not in the case of a string. Why does the behavior differ?
In both cases the compiler does not even throw the Warning: returning address of local variable or temporary as I am returning a reference.
#include <iostream>
#include <string>
using namespace std;
double &getDouble(){
double h = 46.5;
double &refD = h;
return refD;
}
string &getString(){
string str = "Devil Jin";
string &refStr = str;
return refStr;
}
int main(){
double d = getDouble();
cout << "Double = " << d << endl;
string str = getString();
cout << "String = " << str.c_str() << endl;
return 0;
}
Output:
$ ./a.exe
Double = 46.5
String =
You should never return a reference to a local variable no matter what the compiler does or does not do. The compiler may be fooled easily. you should not base the correctness of your code on some warning which may not have fired.
The reason it didn't fire here is probably that you're not literally returning a reference to a local variable, you are returning a variable that is a reference to a local variable. The compiler probably doesn't detect this somewhat more complex situation. It only detects things like:
string &getString(){
string str = "Devil Jin";
return str;
}
The case of the double is simpler because it doesn't involve constructing and destructing a complex object so in this situation the flow control analysis of the compiler probably did a better job at detecting the mistake.
The reference to a double refers to a location that is still physically in memory but no longer on the stack. You're only getting away with it because the memory hasn't been overwritten yet. Whereas the double is a primitive, the string is an object and has a destructor that may be clearing the internal string to a zero length when it falls out of scope. The fact that you aren't getting garbage from your call to c_str() seems to support that.
GCC used to have an extension called Named Returns that let you accomplish the same thing, but allocated the space outside the function. Unfortunately it doesn't exist anymore; I'm not sure why they took it out
Classic case of a Dangling reference in respect to C++.The double variable was not on call stack while returning reference was trying to access it invoking the compiler to set the guarding flags. String however has explicit Garbage Collection mechanism which lets your compiler to overlook the scenario.