C++ 我应该返回 std::strings 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1032243/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Should I return std::strings?
提问by Pedro d'Aquino
I'm trying to use std::string
instead of char*
whenever possible, but I worry I may be degrading performance too much. Is this a good way of returning strings (no error checking for brevity)?
我正在尝试使用std::string
而不是char*
尽可能使用,但我担心我可能会过度降低性能。这是返回字符串的好方法(为简洁起见,没有错误检查)?
std::string linux_settings_provider::get_home_folder() {
return std::string(getenv("HOME"));
}
Also, a related question: when accepting strings as parameters, should I receive them as const std::string&
or const char*
?
另外,一个相关的问题:当接受字符串作为参数时,我应该将它们作为const std::string&
或接收const char*
吗?
Thanks.
谢谢。
采纳答案by duffymo
Return the string.
返回字符串。
I think the better abstraction is worth it. Until you can measure a meaningful performance difference, I'd argue that it's a micro-optimization that only exists in your imagination.
我认为更好的抽象是值得的。在您可以衡量有意义的性能差异之前,我认为这是一种仅存在于您的想象中的微观优化。
It took many years to get a good string abstraction into C++. I don't believe that Bjarne Stroustroup, so famous for his conservative "only pay for what you use" dictum, would have permitted an obvious performance killer into the language. Higher abstraction is good.
将良好的字符串抽象化为 C++ 花了很多年。我不相信 Bjarne Stroustroup 因其保守的“只为你使用的东西付费”的格言而闻名,会允许一个明显的性能杀手进入语言。更高的抽象是好的。
回答by Steve Jessop
Return the string, like everyone says.
返回字符串,就像大家说的那样。
when accepting strings as parameters, should I receive them as const std::string&
or const char*
?
当接受字符串作为参数时,我应该将它们接收为const std::string&
还是const char*
?
I'd say take any const parameters by reference, unless either they're lightweight enough to take by value, or in those rare cases where you need a null pointer to be a valid input meaning "none of the above". This policy isn't specific to strings.
我会说通过引用获取任何 const 参数,除非它们足够轻量级以通过值获取,或者在那些需要空指针作为有效输入的罕见情况下,意思是“以上都不是”。此策略并非特定于字符串。
Non-const reference parameters are debatable, because from the calling code (without a good IDE), you can't immediately see whether they're passed by value or by reference, and the difference is important. So the code may be unclear. For const params, that doesn't apply. People reading the calling code can usually just assume that it's not their problem, so they'll only occasionally need to check the signature.
非常量引用参数是有争议的,因为从调用代码(没有一个好的 IDE),你不能立即看到它们是按值传递还是按引用传递,区别很重要。所以代码可能不清楚。对于 const 参数,这不适用。阅读调用代码的人通常可以假设这不是他们的问题,因此他们只是偶尔需要检查签名。
In the case where you're going to take a copy of the argument in the function, your general policy should be to take the argument by value. Then you already have a copy you can use, and if you would have copied it into some specific location (like a data member) then you can move it (in C++11) or swap it (in C++03) to get it there. This gives the compiler the best opportunity to optimize cases where the caller passes a temporary object.
如果您要在函数中获取参数的副本,您的一般策略应该是按值获取参数。然后你已经有了一个你可以使用的副本,如果你想把它复制到某个特定的位置(比如一个数据成员),那么你可以移动它(在 C++11 中)或交换它(在 C++03 中)到那里去。这为编译器提供了优化调用者传递临时对象情况的最佳机会。
For string
in particular, this covers the case where your function takes a std::string
by value, and the caller specifies as the argument expression a string literal or a char*
pointing to a nul-terminated string. If you took a const std::string&
and copied it in the function, that would result in the construction of two strings.
对于string
在特别地,该盖在您的函数有一个的情况下std::string
通过值,并且调用者指定作为参数表达字符串文字或一个char*
指向一个空终止字符串。如果您将 aconst std::string&
复制到函数中,则会导致构造两个字符串。
回答by jskinner
The cost of copying strings by value varies based on the STL implementation you're working with:
按值复制字符串的成本因您使用的 STL 实现而异:
std::string under MSVC uses the short string optimisation, so that short strings (< 16 characters iirc) don't require any memory allocation (they're stored within the std::string itself), while longer ones require a heap allocation every time the string is copied.
std::string under GCC uses a reference counted implementation: when constructing a std::string from a char*, a heap allocation is done every time, but when passing by value to a function, a reference count is simply incremented, avoiding the memory allocation.
MSVC 下的 std::string 使用短字符串优化,因此短字符串(< 16 个字符 iirc)不需要任何内存分配(它们存储在 std::string 本身中),而较长的需要堆分配每次复制字符串时。
GCC 下的 std::string 使用引用计数实现:当从 char* 构造 std::string 时,每次都进行堆分配,但是当按值传递给函数时,引用计数只是递增,避免了内存分配。
In general, you're better off just forgetting about the above and returning std::strings by value, unless you're doing it thousands of times a second.
一般来说,您最好忘记上述内容并按值返回 std::strings ,除非您每秒执行数千次。
re: parameter passing, keep in mind that there's a cost from going from char*->std::string, but not from going from std::string->char*. In general, this means you're better off accepting a const reference to a std::string. However, the best justification for accepting a const std::string& as an argument is that then the callee doesn't have to have extra code for checking vs. null.
回复:参数传递,请记住,从 char*->std::string 开始是有成本的,但从 std::string->char* 开始没有成本。通常,这意味着您最好接受对 std::string 的 const 引用。然而,接受 const std::string& 作为参数的最佳理由是,被调用者不必有额外的代码来检查与 null。
回答by kostia
Seems like a good idea.
似乎是个好主意。
If this is not part of a realtime software (like a game) but a regular application, you should be more than fine.
如果这不是实时软件(如游戏)的一部分而是常规应用程序的一部分,那么您应该没问题。
Remember, "Premature optimization is the root of all evil"
请记住,“过早优化是万恶之源”
回答by AareP
It's human nature to worry about performance especially when programming language supports low-level optimization. What we shouldn't forget as programmers though is that program performance is just one thing among many that we can optimize and admire. In addition to program speed we can find beauty in our own performance. We can minimize our efforts while trying to achieve maximum visual output and user-interface interactiveness. Do you think that could be more motivation that worrying about bits and cycles in a long run... So yes, return string:s. They minimize your code size, and your efforts, and make the amount of work you put in less depressing.
担心性能是人类的天性,尤其是当编程语言支持低级优化时。作为程序员,我们不应该忘记的是,程序性能只是我们可以优化和欣赏的众多事物中的一件事。除了程序速度之外,我们还可以在自己的表现中发现美。我们可以尽量减少我们的努力,同时尝试实现最大的视觉输出和用户界面交互性。从长远来看,您是否认为这可能比担心位和周期更有动力......所以是的,返回字符串:s。它们最大限度地减少了您的代码大小和工作量,并减少了您投入的工作量。
回答by Kirill V. Lyadvinsky
In your case Return Value Optimization will take place so std::string will not be copied.
在您的情况下,将进行返回值优化,因此不会复制 std::string。
回答by Hans Malherbe
Beware when you cross module boundaries.
当你跨越模块边界时要小心。
Then it's best to return primitive types since C++ types are not necessarily binary compatible across even different versions of the same compiler.
然后最好返回原始类型,因为 C++ 类型不一定在同一编译器的不同版本之间二进制兼容。
回答by Faisal Vali
I agree with the other posters, that you should use string.
我同意其他海报,你应该使用字符串。
But know, that depending on how aggressively your compiler optimizes temporaries, you will probably have some extra overhead (over using a dynamic array of chars). (Note: The good news is that in C++0a, the judicious use of rvalue references will not require compiler optimizations to buy efficiency here - and programmers will be able to make some additional performance guarantees about their code without relying on the quality of the compiler.)
但是要知道,根据您的编译器优化临时变量的积极程度,您可能会有一些额外的开销(超过使用动态字符数组)。(注意:好消息是,在 C++0a 中,明智地使用右值引用不需要编译器优化来提高效率——程序员将能够对其代码做出一些额外的性能保证,而无需依赖于编译器。)
In your situation, is the extra overhead worth introducing manual memory management? Most reasonable programmers would disagree - but if your application does end up having performance issues, the next step would be to profile your application - thus, if you do introduce complexity, you only do it once you have good evidence that it is needed to improve overall efficiency.
在您的情况下,额外的开销值得引入手动内存管理吗?大多数理性的程序员都会不同意——但如果你的应用程序最终确实存在性能问题,下一步将是分析你的应用程序——因此,如果你确实引入了复杂性,只有在你有充分的证据表明需要改进时才这样做整体效率。
Someone mentioned that Return Value optimization (RVO) is irrelevant here - I disagree.
有人提到返回值优化 (RVO) 在这里无关紧要 - 我不同意。
The standard text (C++03) on this reads (12.2):
标准文本 (C++03) 上写着 (12.2):
[Begin Standard Quote]
[开始标准报价]
Temporaries of class type are created in various contexts: binding an rvalue to a reference (8.5.3), returning an rvalue (6.6.3), a conversion that creates an rvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1), entering a handler (15.3), and in some initializations (8.5). [Note: the lifetime of exception objects is described in 15.1. ] Even when the creation of the temporary object is avoided (12.8), all the semantic restrictions must be respected as if the temporary object was created. [Example: even if the copy constructor is not called, all the semantic restrictions, such as accessibility (clause 11), shall be satisfied. ]
类类型的临时对象在各种上下文中创建:将右值绑定到引用 (8.5.3)、返回右值 (6.6.3)、创建右值的转换 (4.1、5.2.9、5.2.11、5.4) ,抛出异常(15.1),进入处理程序(15.3),以及一些初始化(8.5)。[注意:异常对象的生命周期在 15.1 中描述。] 即使避免创建临时对象(12.8),也必须遵守所有语义限制,就像创建临时对象一样。[示例:即使不调用复制构造函数,也应满足所有语义限制,例如可访问性(第 11 条)。]
[Example: struct X { X(int); X(const X&); ?X(); }; X f(X); void g() { X a(1); X b = f(X(2)); a = f(a); }
Here, an implementation might use a temporary in which to construct X(2) before passing it to f() using X's copy-constructor; alternatively, X(2) might be constructed in the space used to hold the argument. Also, a temporary might be used to hold the result of f(X(2)) before copying it to b using X's copyconstructor; alternatively, f()'s result might be constructed in b. On the other hand, the expression a=f(a) requires a temporary for either the argument a or the result of f(a) to avoid undesired aliasing of a. ]
在这里,一个实现可能会使用一个临时对象来构造 X(2),然后使用 X 的复制构造函数将它传递给 f();或者,X(2) 可以在用于保存参数的空间中构造。此外,在使用 X 的复制构造函数将 f(X(2)) 的结果复制到 b 之前,可以使用临时文件来保存它;或者,f() 的结果可能在 b 中构造。另一方面,表达式 a=f(a) 需要参数 a 或 f(a) 的结果的临时变量,以避免出现不希望的 a 别名。]
[End Standard Quote]
【结束标准报价】
Essentially, the text above says that you can possibly rely on RVO in initialization situations, but not in assignment situations. The reason is, when you are initializing an object, there is no way that what you are initializing it with could ever be aliased to the object itself (which is why you never do a self check in a copy constructor), but when you do an assignment, it could.
本质上,上面的文字说你可以在初始化情况下依赖 RVO,但不能在赋值情况下。原因是,当您初始化一个对象时,您所使用的初始化对象不可能成为对象本身的别名(这就是为什么您永远不会在复制构造函数中进行自检),但是当您这样做时一个任务,它可以。
There is nothing about your code, that inherently prohibits RVO - but read your compiler documentation to ensure that you can truly rely on it, if you do indeed need it.
您的代码没有任何本质上禁止 RVO - 但请阅读您的编译器文档以确保您可以真正依赖它,如果您确实需要它。
回答by Gab Royer
Return the string, it's not that big of a loss in term of performance but it will surely ease your job afterward.
返回字符串,就性能而言,这并没有那么大的损失,但它肯定会减轻您之后的工作。
Plus, you could always inline the function but most optimizer will fix it anyways.
另外,您始终可以内联该函数,但大多数优化器无论如何都会修复它。
回答by Brian
I agree with duffymo. You should make an understandable working application first and then, if there is a need, attack optimization. It is at this point that you will have an idea where the major bottlenecks are and will be able to more efficiently manage your time in making a faster app.
我同意达菲莫。您应该首先制作一个可以理解的工作应用程序,然后,如果需要,进行攻击优化。正是在这一点上,您将知道主要瓶颈在哪里,并能够更有效地管理您的时间来制作更快的应用程序。