通过引用将变量传递给函数是否比使函数 return 成为变量更有效?
Would it be more efficient to pass a variable to a function by reference than to make a function to return a variable?
所以这似乎是一个相当简单的问题,但我无法在网上的任何地方找到它的答案。我假设一个 returns 变量的函数比一个接受变量并改变它的函数效率低的原因是因为我认为第一个会使用更多的内存。但是,我可能是错的,我不知道这对处理时间有何影响。
这里有两个 C++ 示例:
这是一个 returns 变量的函数:
#include <iostream>
short getInput(){
short input;
std::cin >> input;
return input;
}
int main(){
short input = getInput();
}
您可以在此看到程序需要创建两个输入变量,即使第二个变量只创建了很短的时间。
这是一个通过引用传递值的函数:
#include <iostream>
short getInput(short& input){
std::cin >> input;
}
int main(){
short input;
getInput(input);
}
这个示例代码段不仅更短,而且只初始化了一个短变量。我是不是错了,它更有效率。
像 short
或 int
这样的小而简单的内置类型的值几乎肯定会 return 在寄存器中编辑,因此它不会涉及创建任何东西。
如果我们将您的代码稍微简化为 return 1;
之类的代码,我们希望正文(当我们关闭优化时,仍然有任何代码)我们最终会像这样:
mov rax, 1
ret
如果 return 值 不够 小到可以放入寄存器,那么编译器通常会在调用者中分配 space,并将对该 space 的隐藏引用传递给被调用的函数。换句话说,它会做你手动做的基本相同的事情。
长话短说,您应该以最合理的方式编写代码。如果 if 对您的函数最有意义 return 一个值,那么 return 一个值。如果传递引用更有意义,那么就这样做。
在某些情况下,修改引用变量而不是 return修改值才有意义。一个是来自堆栈或队列的 pop
之类的东西。如果复制 return 值可能会抛出异常,那么异常安全性可能会有所不同。例如,您可以这样做:
template <class T>
class queue {
std::deque<T> data;
public:
void pop(T &t) {
t = data.front();
data.pop_front();
}
};
如果您尝试按值 return T,您最终可能会从双端队列中弹出该值,但是当您尝试复制 return 值时,它的复制构造函数会抛出。
但是,通过这种方式,如果复制到 "return" 值成功,您只会从双端队列中弹出值。如果副本抛出,则该值保留在双端队列中。
我会尝试回答,尽管我确定它可能值得商榷。我强烈支持 return 按值而不是使用输出参数,原因如下:
按值返回基本类型非常有效。按值返回还允许 "natural" 函数组合,例如
double result = sin(exponential(factorial(n)));
想象一下用所有 3 个函数的输出参数编写此代码。
每当您 return 大型 class 对象时,性能就开始变得重要。然而,在那种情况下,编译器可以(并且确实)执行所谓的 (named) return value optimization。这是一种优化方案,其中(命名的)return 值直接构造到左侧对象中(有一些限制,请参阅 link)。此外,return按值与 C++11 移动语义配合得很好,所以如果你有某种类型的廉价移动对象,比如 Foo
,你可以写
my_already_constructed_object = some_function_that_returns_by_value();
并且移动赋值运算符会发挥它的魔力,这实际上比深拷贝便宜得多(把它想象成交换)。
所以这似乎是一个相当简单的问题,但我无法在网上的任何地方找到它的答案。我假设一个 returns 变量的函数比一个接受变量并改变它的函数效率低的原因是因为我认为第一个会使用更多的内存。但是,我可能是错的,我不知道这对处理时间有何影响。
这里有两个 C++ 示例: 这是一个 returns 变量的函数:
#include <iostream>
short getInput(){
short input;
std::cin >> input;
return input;
}
int main(){
short input = getInput();
}
您可以在此看到程序需要创建两个输入变量,即使第二个变量只创建了很短的时间。
这是一个通过引用传递值的函数:
#include <iostream>
short getInput(short& input){
std::cin >> input;
}
int main(){
short input;
getInput(input);
}
这个示例代码段不仅更短,而且只初始化了一个短变量。我是不是错了,它更有效率。
像 short
或 int
这样的小而简单的内置类型的值几乎肯定会 return 在寄存器中编辑,因此它不会涉及创建任何东西。
如果我们将您的代码稍微简化为 return 1;
之类的代码,我们希望正文(当我们关闭优化时,仍然有任何代码)我们最终会像这样:
mov rax, 1
ret
如果 return 值 不够 小到可以放入寄存器,那么编译器通常会在调用者中分配 space,并将对该 space 的隐藏引用传递给被调用的函数。换句话说,它会做你手动做的基本相同的事情。
长话短说,您应该以最合理的方式编写代码。如果 if 对您的函数最有意义 return 一个值,那么 return 一个值。如果传递引用更有意义,那么就这样做。
在某些情况下,修改引用变量而不是 return修改值才有意义。一个是来自堆栈或队列的 pop
之类的东西。如果复制 return 值可能会抛出异常,那么异常安全性可能会有所不同。例如,您可以这样做:
template <class T>
class queue {
std::deque<T> data;
public:
void pop(T &t) {
t = data.front();
data.pop_front();
}
};
如果您尝试按值 return T,您最终可能会从双端队列中弹出该值,但是当您尝试复制 return 值时,它的复制构造函数会抛出。
但是,通过这种方式,如果复制到 "return" 值成功,您只会从双端队列中弹出值。如果副本抛出,则该值保留在双端队列中。
我会尝试回答,尽管我确定它可能值得商榷。我强烈支持 return 按值而不是使用输出参数,原因如下:
按值返回基本类型非常有效。按值返回还允许 "natural" 函数组合,例如
double result = sin(exponential(factorial(n)));
想象一下用所有 3 个函数的输出参数编写此代码。
每当您 return 大型 class 对象时,性能就开始变得重要。然而,在那种情况下,编译器可以(并且确实)执行所谓的 (named) return value optimization。这是一种优化方案,其中(命名的)return 值直接构造到左侧对象中(有一些限制,请参阅 link)。此外,return按值与 C++11 移动语义配合得很好,所以如果你有某种类型的廉价移动对象,比如
Foo
,你可以写my_already_constructed_object = some_function_that_returns_by_value();
并且移动赋值运算符会发挥它的魔力,这实际上比深拷贝便宜得多(把它想象成交换)。