It greatly depends on the task at hand. I would go for the first approach for functions that create new values while using the second approach for functions that change the parameters. As mentioned by others, in some cases other restrictions (cost of creation / assignment) can affect the decision.
The first definition is clearly stating that it will create a new object out of nothing and will return it. That is, the same definition is stating the semantics of the call.
The second and third definitions require the caller to create an object before calling the function. This can be a hassle to the user as she cannot just ignore the return value (or use it as an unnamed temporal to feed another function, see snippet 1), and can be limited in cases (i.e. cannot reassign a reference from an already created object, see snippet 2).
It is not clear from the function definition what is the use of the parameter inside the function. Will the behavior of the function differ depending on the passed object? It is not clear from the function definition.
The third type is, I believe, the worst option. Not only it forces the caller to create a named variable to pass to the function but also makes a copy to return (unless it was a typo and you are returning a [possibly const] reference)
At any rate, other considerations can unbalance the advantage of clear semantics that the first approach provides. In some cases performance, or other limitations like objects that cannot be copied (see snippet 3)
// snippet 1
// user code to the different approaches
class X {};
X f1();
void f2( X& );
X f3( X& );
void g( X const & );
void test1()
{
g( f1() ); // valid code
}
void test2()
{
X x; // must create instance before
f2( x ); // then call the function
g( x );
}
void test3()
{
X x; // must create instance before
g( f3( x ) );
}
// snippet 2
class Y {};
class X
{
public:
X( Y & y ) : y_( y ) {}
private:
Y & y_;
};
X f1();
void f2( X & );
X f3( X & );
void test1()
{
X x = f1();
}
void test2or3()
{
Y y;
X x( y ); // user must create with a reference
f2( x ); // f2 cannot change the reference inside x to another instance
}
// snippet 3
class X
{
private:
X( X const & );
X& operator= ( X const & );
};
X f1(); // Returned object cannot be used
void f2( X & );
X f3( X & );
void test1()
{
X x = f1(); // compilation error
}
void test2()
{
X x;
f2( x );
}
void test3()
{
X x;
X y = f3( x ); // compilation error
}