Reputation: 4017
I am following this tutorial - http://www.learncpp.com/cpp-tutorial/132-function-template-instances/
// passing all parameters by references
template <typename T1, typename T2>
const T2& add_two_objects(const T1& x,const T2& y) {
return x+y;
};
int main() {
using std::cout;
int x(0),y(0);
std::cout << "Please enter number 1" << std::endl;
std::cin >> x;
std::cout << "Please enter number 2" << std::endl;
std::cin >> y;
cout<< "sum of two integers is " << add_two_objects(x,y+1.2) << '\n';
cout<< "sum of two double is " << add_two_objects(x,y+2.52424324) << '\n';
return 0;
}
The program compiles fine, but at the run time, I always get a segmentation fault. However if I change the template to pass by value, then everything works.
// passing all parameters by value
template <typename T1, typename T2>
const T2 add_two_objects(const T1 x,const T2 y) {
return x+y;
};
Can anyone please explain?
Upvotes: 1
Views: 68
Reputation: 45484
This
template <typename T1, typename T2>
const T2& add_two_objects(const T1& x, const T2& y) {
return x+y;
};
returns a reference to a temporary. Make the return a value
template <typename T1, typename T2>
T2 add_two_objects(const T1& x, const T2& y) {
return x+y;
};
and you should be fine.
Btw, it's not clear that returning a T2
is the best thing to do here. Consider for example the case T1=size_t
and T2=char
. Better to return the type that the operation x+y
actually generates
template <typename T1, typename T2>
auto add_two_objects(const T1& x, const T2& y)
-> decltype(x+y)
{
return x+y;
};
------edit-----
You must not return a reference to a temporary object. It's a BUG. If you want a bug, go for it. And you should not use poor tutorials. There are situations when you want/should return a reference, but this is not one of them. These are when the reference is to an object that will not be destroyed (or go out of scope) when returning form the function (as all automatic and temporary variables will).
Upvotes: 6
Reputation: 311156
To make it more clear let's wrap the integers in structures.
Here is a demonstrative program
#include <iostream>
struct A
{
A( int x ) : x( x ) {}
~A() { std::cout << "[A::~A() is called for x = " << x << ']' << std::endl; }
int x;
};
A operator +( const A &lhs, const A &rhs )
{
return A( lhs.x + rhs.x );
}
std::ostream & operator <<( std::ostream &os, const A &a )
{
return os << a.x;
}
template <typename T1, typename T2>
const T2& add_two_objects(const T1& x,const T2& y) {
return x+y;
};
int main()
{
std::cout<< "sum of two integers is " << add_two_objects( A( 1 ), A( 2 ) ) << '\n';
return 0;
}
Its output might look like
prog.cc:22:18: warning: returning reference to temporary [-Wreturn-local-addr]
return x+y;
^
sum of two integers is [A::~A() is called for x = 3]
Segmentation fault
First of all the compiler warns that the function returns reference to a temporary value. That is after exiting the function the temporary object will be destroyed and this output
[A::~A() is called for x = 3]
confirms this.
As result the reference will be invalid and the program has undefined behavior.
In fact you can imagine the program logic the following way
int main()
{
const A &r = add_two_objects( A( 1 ), A( 2 ) );
std::cout<< "sum of two integers is " << r << '\n';
return 0;
}
Its output looks almost similar as in the above program
prog.cc:22:18: warning: returning reference to temporary [-Wreturn-local-addr]
return x+y;
^
[A::~A() is called for x = 3]
[A::~A() is called for x = 1]
[A::~A() is called for x = 2]
Segmentation fault
That is the reference becomes invalid.
If to remove the reference in the function declaration
template <typename T1, typename T2>
const T2/*&*/ add_two_objects(const T1& x,const T2& y) {
return x+y;
};
then the program output might look like
sum of two integers is 3
[A::~A() is called for x = 3]
[A::~A() is called for x = 1]
[A::~A() is called for x = 2]
Upvotes: 1