views:

125

answers:

4

I tried following code :

#include<iostream> 
#include<string>
using namespace std;

string f1(string s)
{
   return s="f1 called";
}

void f2(string *s)
{
   cout<<*s<<endl;
}

int main()
{
   string str;
   f2(&f1(str));
}

But this code doesn't compile.
What I think is : f1 returns by value so it creates temporary, of which I am taking address and passing to f2.
Now Please explain me where I am thinking wrong?

+1  A: 

Your program doesn't compile because f1 has a parameter and you're not passing any.

Additionally, the value returned from a function is an rvalue, you can't take its address.

avakar
Oh...My bad.But it is still giving warning : "taking address of temporary"
Happy Mittal
Happy Mittal, yes, because it is an rvalue. Imagine the function returning an `int` instead of a `string`, it may be more obvious -- the value being returned need not have any corresponding memory location.
avakar
+4  A: 

The unary & takes an lvalue (or a function name). Function f1() doesn't return an lvalue, it returns an rvalue (for a function that returns something, unless it returns a reference, its return value is an rvalue), so the unary & can't be applied to it.

James McNellis
But I am able to use f1() like this :f1(str)="happy";Here I am using temporary as l-value.
Happy Mittal
Happy Mittal, the word lvalue may be a little confusing -- it no longer means "a value that can stand on the left side of an assignment". when you use the `=` operator, you are in fact calling a member function of the string object. You are allowed to use members of rvalues.
avakar
So what would happen if string had an explicit operator}?
James McNellis
+1  A: 

Try this:

int main()
{
    string str;
    string str2 = f1(str); // copy the temporary
    f2(&str2);
}
egrunin
That's one unnecessary copy. (_If you don't mind needlessly copying strings, why bother with C++ at all?_) If you bind an rvalue to a `const` reference, the rvalue's lifetime will be extended to the end of the reference's lifetime. So `const std::string` is what you want.
sbi
@sbi: My example, like his, is much simpler than any real-world code.
egrunin
Note that your answers are to teach people how to do things they don't know yet. Even though you only omit something because it's not relevant to your argument, others might still pick up a wrong habit from it.
sbi
+2  A: 

It is possible to create (and pass) a pointer to a temporary object, assuming that you know what you are doing. However, it should be done differently.

A function with return value of non-reference type returns an rvalue. In C++ applying the built-in unary operator & to an rvalue is prohibited. It requires an lvalue.

This means, that if you want to obtain a pointer to your temporary object, you have to do it in some other way. For example, as a two-line sequence

const string &r = f1(str);
f2(&r);

which can also be folded into a single line by using a cast

f2(&(const string &) f1(str));

In both cases above the f2 function should accept a const string * parameter. Just a string * as in your case won't work, unless you cast away constness from the argument (which, BTW, will make the whole thing even uglier than it already is). Although, if memory serves me, in both cases there's no guarantee that the reference is attached to the original temporary and not to a copy.

Just keep in mind though creating pointers to temporary objects is a rather dubious practice because if the obvious lifetime issues. Normally you should avoid the need to do that.

AndreyT