参考或返回-最佳实践
reference or return - best practice
例如,我们有编码函数。最佳实践是什么:
void Crypto::encoding(string &input, string &output)
{
//encoding string
output = encoded_string;
}
或
string Crypto::encoding(string &input)
{
//encoding string
return encoded_string;
}
应该使用reference还是return返回字符串?据我所知,返回一个字符串需要一些时间来初始化一个将由return指令返回的新字符串。当使用引用变量时,我不会浪费时间初始化一些新变量,我只是结束函数。
我们应该主要使用引用并使函数返回类型为void吗?或者当我们想要返回两个或多个变量时,我们应该只通过引用返回数据,当我们需要返回一个变量时,使用return指令?
不要优化你没有测量的东西
通常用return
返回计算结果会更好(更可读)。如果因为对象太大而花费了很长时间,您仍然可以通过引用参数返回结果,但只有在您证明这将导致性能的显着改进之后(测量它)。例如,如果你只编码非常短的字符串,并且只在一段时间内这样做,那么复制的开销可以忽略不计。
由于大多数现代编译器都具有RVO特性,因此通常会消除复制内容。即使没有c++11,您也可以从中获益。
如果您的编译器支持c++ 11标准和r值引用,那么按值返回std::string实际上是相当有效的。在此功能之前,答案可能略有不同,因为您只依赖编译器执行RVO。
我想说,使用返回值可能更自然,也意味着你可以将结果分配给一个恒定的局部变量或类成员,以避免意外修改,例如
const std::string result = crypo.encoding("blah");
或
class SomeClass
{
public:
Someclass(Crypto& crypto, const std::string& input) :
m_output(crypo.encoding(input))
{
}
private:
const std::string m_output;
};
只要确保不以const值返回,因为这会抑制move语义。
我使用引用。这允许实现者做出和抽象选择,而不会给客户端带来沉重的负担(有些情况很重要,有些情况不会)。
我也使用它们来保持风格的一致性——我不喜欢看到通过传递其实现细节的公共接口。
瞬态和副本可能是昂贵的——它因传递的类型而有很大差异。按值返回表明类型应该是可构造的、可互换的、可复制的、可移动的。编译器可以在这方面做一些很好的优化(RVO/move),但是您也可以做出明智的决定来最小化实现中昂贵的操作。一旦您不再使用所有人都知道其复制特征的类型,那么选择如何返回就会变得非常复杂,因此我只保持简单并使用引用。
传递引用还有其他一些好处,比如当客户端更喜欢使用传递的类型的子类时。
如果您需要一个优化的程序,另一个好处是:我经常删除复制因子和operator=
,如果它们不是微不足道的或可能的。通过可变引用传递可以使用不可复制/赋值的类型。
在这个问题中使用的std::string
的严格范围内:按值返回std::string
是很常见的,并且针对这种情况进行了许多优化- RVO, COW和move是一些值得注意的优化。正如Voo在下面的评论中提到的,按值返回通常更容易阅读。在std::string
和更高级别程序的情况下,按值返回不太可能是一个问题,但是如果性能很重要(您的问题表明可能是这种情况),为了了解您正在使用的标准库实现所涉及的成本,进行度量是很重要的。
一个重要的考虑是,如果您试图改进现有的程序,请确保您了解实现是如何执行的,并了解如何在性能很重要的情况下最有效地使用类型。实现可能是为的实际使用而编写和优化的,这意味着它们在某些情况下可能是悲观的,并且会对您进行事后猜测,并且您改进性能的尝试可能已经实现,或者非常规地使用该类型可能会降低的性能。std::vector
的典型调整大小行为就是一个明显的例子。走高性能之路确实会增加大量的时间和复杂性,因为要获得最佳结果需要了解哪些内容,这显然会因所使用的实现和所使用的类型而异。如果性能是至关重要的,并且值得投入大量的时间,那么学习使用的类型的操作是一项值得的努力,可以带来显著的收益。
我还应该补充说,我经常在低级别工作——在那里,性能至关重要和/或资源有限。可以有许多限制,包括没有异常、没有锁(也意味着没有堆分配)、最小的抽象成本,甚至限制动态多态性的使用。它可以被认为是一个相当苛刻的领域,即使对于c++也是如此。我为核心的低级部分选择引用,但是如果我知道一个程序将只在高级领域或单元测试中使用,我将放宽这一规则。
在新的标准c++ 11中,由于新的move语义,您可以使用第二个变体。
然而,最有可能的是,您的编译器仍然只支持旧的标准。在这种情况下,您的第一个示例不会引起任何复制,而且更好。我郑重声明:可能两者都不是。
你的encode
在我看来很像一个通用算法,它应该真正使用迭代器,而不是直接处理字符串。
template <class InputIterator, class OutputIterator>
void encode(InputIterator begin, InputIterator end, OutputIterator result) {
while (begin!=end)
*result++ = encode_byte(*begin++);
}
这样,你可以(例如)很容易地重用完全相同的代码来直接从输入流(通过std::istream_iterator
)到输出流(通过std::ostream_iterator
)编码数据。
这通常也消除了大多数关于效率的问题。
我更喜欢第二个版本,因为它看起来更像一个数学函数。如果你只返回字符串,你应该有良好的性能。
- 使用作为参数返回的指针的最佳做法是什么
- 以最佳方式返回复制的值
- 从C 中的函数中动态分配的缓冲区返回的最佳模式是什么?
- 编写两个方法的最佳方法,这些方法在C++中返回同一项的值和引用
- 返回可能在C++中分配在堆栈上的成员时,最佳指针/引用类型是什么
- 拥有 std::map 的最佳方式,我可以在其中定义如果没有键时返回的内容
- C++/如何返回最佳时间结果
- 用C++编写返回对象的函数的最佳方法是什么
- 用C++返回类的最佳方法
- 将元组传递给函数并让它返回数字列表的最佳方法
- 工厂函数的最佳智能指针返回类型是什么
- 使用具有返回值的访客模式实现 AST 的最佳方法是什么?
- C++从函数调用的多个返回中构建字符串向量的最佳方法
- 返回转发引用参数 - 最佳做法
- std::optional 的最佳替代方案是从方法返回可选值?(使用 C++98/C++11/C++14)
- 返回指针的最佳方式
- 返回一组数据类型之一的最佳模式
- 从 c++ 中的函数返回向量的最佳方法是什么
- 在C++中返回字符串的最佳方法是什么
- 返回指向嵌套 std::vector 项的指针的最佳方法