当函数(被调用者)向调用函数返回一个数量时,它是否返回 价值或参考?
问题是我编写了一个函数,它在调用时构建了一个非常大的向量。我想通过常量引用将>>这个大向量返回到调用函数(在本例中为main()
),这样我就可以对它进行一些进一步的处理。
我有点怀疑,因为有人告诉我,当C ++函数返回并终止时,与该函数关联的所有变量/内存都会被清除干净。
struct node{
string key;
int pnum;
node* ptr;
}
vector< vector<node> > myfun1(/*Some arguments*/)
{
/*Build the vector of vectors. Call it V*/
return v;
}
int main(void)
{
a=myfun1(/* Some arguments */)
}
答案 0 :(得分:26)
C ++函数可以按值返回,通过引用返回(但不通过引用返回本地变量),或者通过指针返回(同样,不要通过指针返回本地)。
当按值返回时,编译器通常可以进行优化,使其与通过引用返回一样快,而不会出现悬空引用的问题。这些优化通常称为“返回值优化(RVO)”和/或“命名返回值优化(NRVO)”。
调用者提供空向量(通过引用)的另一种方法,并让函数填充它。然后它不需要返回任何内容。
你绝对应该阅读这篇博文:Want Speed? Pass by value.
答案 1 :(得分:24)
默认情况下,C / C ++中的所有内容都按值传递,包括返回类型,如下例所示:
T foo() ;
在C ++中,类型通常被认为是值类型(即它们的行为类似于int
或double
类型),如果对象的构造/破坏不是微不足道的话,额外的副本可能会很昂贵。
如果要通过引用或指针返回,则需要将返回类型更改为:
T & foo() ; // return a reference
T * foo() ; // return a pointer
但在这两种情况下,您需要确保返回后返回的对象仍然存在。例如,如果返回的对象是在函数体中的堆栈上分配的,则该对象将被销毁,因此其引用/指针将无效。
如果您无法保证返回后对象仍然存在,那么您唯一的解决方案是:
void foo(T & t) ;
这样,在函数内部,您可以根据需要设置t
值,并在函数返回后获得结果。
现在,如果您有机会使用C ++ 0x / C ++ 11,即使用支持r-values references/move semantics的编译器,如果您的对象具有正确的构造函数/运算符(如果您的对象)来自标准库,然后就可以了,然后额外的临时副本将被优化掉,你可以保留符号:
T foo() ;
知道编译器不会生成不必要的临时值。
答案 2 :(得分:4)
它是由您声明的返回类型返回的。 vector<int> f();
和vector<int>& f();
分别按值和引用返回。但是,在函数中返回对局部变量的引用将是一个严重错误,因为当函数范围退出时它将被吹走。
有关如何从函数中有效返回大向量的好提示,请参阅this question(实际上这个可以说与此重复)。
答案 3 :(得分:2)
该函数将返回您告诉它返回的内容。如果要返回vector
,则它将被调用者复制到变量hold。除非您通过const引用捕获该结果,否则无需复制它。有一些优化允许函数通过将结果放在将保存返回值的对象中来避免这种额外的复制构造。在更改设计性能之前,您应该阅读此内容:
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
答案 4 :(得分:2)
C ++可以通过引用或值返回。如果要返回引用,则必须将其指定为返回类型的一部分:
std::vector<int> my_func(); // returns value
std::vector<int>& my_func(); // returns reference
std::vector<int> const& my_func(); // returns constant reference
函数返回时,在函数内创建的所有局部(堆栈)变量都将被销毁。这意味着你绝对不应该通过引用或const引用(或指向它们的指针)返回本地。如果按值返回向量,则可以在销毁本地之前复制 ,这可能会很昂贵。 (称为“返回值优化”的某些类型的优化有时可以删除副本,但这不属于这个问题的范围。要判断优化是否会发生在特定的代码片段上并不总是很容易。)
如果你想在函数内部“创建”一个大的向量,然后在不复制的情况下返回它,最简单的方法是将向量作为参考参数传递给函数:
void fill_vector(std::vector<int> &vec) {
// fill "vec" and don't return anything...
}
另请注意,在最近批准的新版C ++标准(称为C ++ 0x或C ++ 11)中,按函数返回值的本地向量将而不是实际复制向量,它将被有效移动到其新位置。执行此操作的代码看起来与以前版本的C ++中的代码相同,可以强制复制该向量。请与您的编译器一起检查它是否支持“移动语义”(C ++ 11标准中使其成为可能的部分)。
答案 5 :(得分:0)
与C ++中的大多数事情一样,答案是“这取决于你如何定义函数”。
该语言的默认值是按值返回。像“double f()”之类的简单调用将始终按值返回浮点数。但是,您可以通过指针或引用返回值 - 您只需添加额外符号'&amp;'或'*'到返回类型:
// Return by pointer (*)
T* f();
// Return by reference (a single '&')
T& f();
然而,在许多情况下,这些都是非常不安全的。如果函数返回的值是在函数内声明的,则返回的引用或指针将指向随机垃圾而不是有效数据。即使你可以保证指向的数据仍然存在,但是这种返回通常比所有现代C ++编译器为你做的优化更加麻烦。通过引用返回内容的惯用,安全的方法是将命名引用作为参数传递:
// Return by 'parameter' (a logical reference return)
void f(T& output);
现在输出有一个真实的名字,我们知道它将在通话中存活,因为它必须存在才能调用'f'。这是您在C ++中经常会看到的模式,特别是对于填充STL std :: vector之类的东西。它的丑陋,但直到C ++ 11的出现,它通常比简单地按值返回向量更快。现在,即使对于许多复杂类型,按值返回也更简单,更快,您可能看不到许多函数遵循旧库之外的引用返回参数模式。
答案 6 :(得分:-5)
退出时清除堆栈上定义的所有变量。 要返回变量,您应该在堆上分配它,使用new关键字(或malloc)。
类和结构作为指针传递,而基元类型作为值传递。