功能模板按值和参考差异

时间:2017-06-16 16:21:21

标签: c++ reference temporary-objects

我正在关注本教程 - 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;
}

程序编译很好,但在运行时,我总是遇到分段错误。但是,如果我将模板更改为按值传递,则一切正常。

// passing all parameters by value
template <typename T1, typename T2>
const T2 add_two_objects(const T1 x,const T2 y) {
        return x+y;
};

有人可以解释一下吗?

2 个答案:

答案 0 :(得分:6)

template <typename T1, typename T2>
const T2& add_two_objects(const T1& x, const T2& y) {
        return x+y;
};

返回对临时的引用。使返回值为

template <typename T1, typename T2>
T2 add_two_objects(const T1& x, const T2& y) {
        return x+y;
};

你应该没事。

不过,目前尚不清楚返回T2是最好的事情。例如,考虑案例T1=size_tT2=char。最好返回操作x+y实际生成的类型

template <typename T1, typename T2>
auto add_two_objects(const T1& x, const T2& y)
-> decltype(x+y)
{
    return x+y;
};

------ -----编辑

不得返回对临时对象的引用。这是一个 BUG 。如果你想要一个bug,那就去吧。你不应该使用糟糕的教程。在某些情况下,您希望/应该返回引用,但这不是其中之一。这些是当引用函数返回时不会被销毁(或超出范围)的对象(如所有自动和临时变量那样)。

答案 1 :(得分:1)

为了更清楚,让我们将整数包裹在结构中。

这是一个示范程序

#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;
}

它的输出可能看起来像

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

首先,编译器警告该函数返回对临时值的引用。那是在退出函数后,临时对象将被销毁并输出

[A::~A() is called for x = 3]

证实了这一点。

结果,引用将无效,程序具有未定义的行为。

实际上你可以通过以下方式想象程序逻辑

int main() 
{
    const A &r = add_two_objects( A( 1 ), A( 2 ) );
    std::cout<< "sum of two integers is " << r << '\n';

    return 0;
}

它的输出看起来与上面的程序

几乎相似
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

即参考无效。

如果要删除函数声明中的引用

template <typename T1, typename T2>
const T2/*&*/ add_two_objects(const T1& x,const T2& y) {
        return x+y;
};

然后程序输出可能看起来像

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]