C++ 通过引用传递向量的尾部递归

C++ 通过引用传递向量的尾部递归,c++,recursion,pass-by-reference,tail-recursion,C++,Recursion,Pass By Reference,Tail Recursion,考虑一个尾部递归的例子 int foo(vector<int> &vec, int n) { if (n == 1) return vec[0]; vector<int> new_vector = createNewVector(vec); return foo(new_vector, n-1); } intfoo(向量&vec,intn) { 如果(n==1)返回向量[0]; vector new

考虑一个尾部递归的例子

int foo(vector<int> &vec, int n)
{
    if (n == 1) return vec[0];      
    vector<int> new_vector = createNewVector(vec);              
    return foo(new_vector, n-1);
}
intfoo(向量&vec,intn)
{
如果(n==1)返回向量[0];
vector new_vector=createNewVector(vec);
返回foo(新的_向量,n-1);
}
其中
createNewVector(vec)
是返回与
vec
大小相同的新向量的任何函数

我担心编译器无法将其检测为尾部递归,因为
vec
是通过引用传递的(不能删除上一个堆栈帧,因为
vec
引用点指向上一个
new_vector
)。在这种情况下,用于此递归的内存将是
O(n*vec.size())
,因为前面的每个堆栈帧都包含
vec.size()
元素

这是真的,还是可以将此函数优化为尾部递归?

在这种情况下,尾部递归(TCO)是不可能的。必须在递归调用返回后调用
new_vector
析构函数,这完全消除了TCO的可能性

一般来说,当非平凡类型的自动变量起作用时,自动对象的析构函数使编译器很难参与TCO,并且在示例中通过值或引用传递向量不会产生任何影响-TCO仍然没有发生。

在这种情况下,尾部递归(TCO)是不可能的。必须在递归调用返回后调用
new_vector
析构函数,这完全消除了TCO的可能性


一般来说,当非平凡类型的自动变量起作用时,自动对象的析构函数使得编译器很难进行TCO,在您的示例中,通过值或引用传递向量并没有什么区别-TCO仍然没有发生。

gcc和clang在这里不做尾部递归:尾部递归无论如何都不能保证。你是对的——在这种情况下,这可能是不可能的。FWIW
intfoo(vector-vec,intn)
returnfoo(createNewVector(vec),n-1)
May.gcc和clang在这里不做尾部递归:无论如何,尾部递归都不能保证。你是对的——在这种情况下,这可能是不可能的。FWIW
intfoo(vector-vec,intn)
returnfoo(createNewVector(vec),n-1)可能。只是确认一下。如果我通过值而不是引用传递
vec
,那么我将有尾部递归。@Dejan,仍然需要调用
std::vector
的-destructor。需要调用destructor,但据我所知,尾部递归的目的是在递归调用之前调用该析构函数,并删除上一个堆栈帧。因此,将调用析构函数,这将是一个尾部递归。对吗?@Dejan,没有。在尾部调用返回后必须调用析构函数。@Dejan,
n
是一个整数参数,因此没有要为它调用的析构函数。相反,
std::vector
有一个析构函数,这是一个函数,需要在递归函数返回之后,但在允许调用方函数返回之前调用它。请确认。如果我通过值而不是引用传递
vec
,那么我将有尾部递归。@Dejan,仍然需要调用
std::vector
的-destructor。需要调用destructor,但据我所知,尾部递归的目的是在递归调用之前调用该析构函数,并删除上一个堆栈帧。因此,将调用析构函数,这将是一个尾部递归。对吗?@Dejan,没有。在尾部调用返回后必须调用析构函数。@Dejan,
n
是一个整数参数,因此没有要为它调用的析构函数。相反,
std::vector
有一个析构函数,这是一个函数,需要在递归函数返回之后,但在允许调用方函数返回之前调用它。