我应该返回std ::string?
我试图尽可能使用std::string
而不是char*
,但是我担心可能会降低性能。 这是一个返回string的好方法(为简洁起见没有错误检查)?
std::string linux_settings_provider::get_home_folder() { return std::string(getenv("HOME")); }
此外,一个相关的问题:当接受string作为参数,我应该收到他们作为const std::string&
或const char*
?
谢谢。
返回string。
我认为更好的抽象是值得的。 直到你可以衡量一个有意义的性能差异,我认为这是一个微观优化,只存在于你的想象中。
花了很多年才把一个好的string抽象成C ++。 我不相信Bjarne Stroustroup,因为他的保守派“只付出你所用的”这个名言而闻名,将会允许一个明显的表演杀手进入这个语言。 更高的抽象是好的。
像所有人都说的那样返回string。
当接受string作为参数,我应该收到他们作为const std::string&
或const char*
?
我会说,通过引用采取任何const参数,除非他们是足够轻量级的价值,或在罕见的情况下,你需要一个空指针是一个有效的input意思是“以上都不是”。 这个政策并不特定于string。
非常量引用参数是有争议的,因为从调用代码(没有一个好的IDE),你不能立即看到它们是按值还是按引用传递的,差别很重要。 所以代码可能不清楚。 对于const params,这不适用。 阅读调用代码的人通常可以认为这不是他们的问题,所以他们只会偶尔需要检查签名。
如果你要在函数中取一个参数的副本,那么你的一般策略应该是按照价值来论证。 那么你已经有一个你可以使用的副本,如果你将它复制到某个特定的位置(如数据成员),那么你可以移动它(在C + + 11)或交换(在C + + 03)在那里得到它。 这给了编译器最好的机会来优化调用者传递临时对象的情况。
对于string
,这涵盖了你的函数通过值接受一个std::string
的情况,调用者将参数expression式指定为一个string或一个char*
指向一个以nul结尾的string。 如果你把一个const std::string&
复制到函数中,那将导致两个string的构造。
按值复制string的成本取决于您正在使用的STL实现:
-
MSVC中的std :: string使用短string优化,因此短string(<16个字符iirc)不需要任何内存分配(它们存储在std :: string本身内),而较长的string需要堆分配每次string被复制。
-
在GCC下的std :: string使用引用计数的实现:当从char *构造一个std :: string时,每次都进行一次堆分配,但是当通过值传递给一个函数时,引用计数会简单地增加,避免内存分配。
一般来说,你最好忘记上面的内容,并按值返回std :: strings,除非你每秒处理数千次。
重新:parameter passing,请记住从char * – > std :: string,而不是从std :: string-> char *。 一般来说,这意味着你最好接受一个std :: string的const引用。 然而,接受一个const std :: string&作为参数的最佳理由是被调用者不必为检查和空值而添加额外的代码。
似乎是个好主意。
如果这不是一个实时软件(如游戏),而是一个普通的应用程序的一部分,你应该是很好的。
请记住,“ 过早优化是万恶之源 ”
在你的情况下,返回值优化将发生,所以std :: string将不会被复制。
特别是在编程语言支持低级优化时,担心性能是人为的本性。 作为程序员,我们不应该忘记,程序性能只是我们可以优化和欣赏的许多内容之一。 除了程序速度,我们可以在自己的performance中find美。 我们可以尽量减less我们的努力,同时努力实现最大的视觉输出和用户界面的交互性。 你认为这可能是更长久的动力,担心位和循环…所以是的,返回string:s。 他们尽量减less你的代码大小和你的努力,并使你所投入的工作量减less。
当你跨越模块边界时要小心。
那么最好返回原始types,因为即使不同版本的同一个编译器,C ++types也不一定是二进制兼容的。
我同意其他海报,你应该使用string。
但要知道,取决于编译器如何优化临时对象,您可能会有额外的开销(通过使用dynamic数组的字符)。 (注意:好消息是,在C ++ 0a中,右值引用的谨慎使用不需要编译器优化来提高效率 – 程序员将能够在不依赖质量的前提下为其代码提供额外的性能保证编译器。)
在你的情况下,值得引入手动内存pipe理的额外开销是多less? 大多数合理的程序员会不同意 – 但是如果你的应用程序最终会遇到性能问题,那么下一步就是分析你的应用程序 – 因此,如果你确实引入了复杂性,那么只有当你有充分的证据certificate需要改进时整体效率。
有人提到,返回值优化(RVO)在这里是无关的 – 我不同意。
标准文本(C ++ 03)读取(12.2):
[开始标准报价]
类types的临时类在各种上下文中创build:将一个右值绑定到一个引用(8.5.3),返回一个右值(6.6.3),一个右值(4.1,5.2.9,5.2.11,5.4) ,抛出exception(15.1),input处理程序(15.3),以及在一些初始化(8.5)中。 [注意:exception对象的生命周期在15.1中描述。 ]即使避免了临时对象的创build(12.8),也必须遵守所有的语义限制,就像临时对象被创build一样。 [例如:即使复制构造函数没有被调用,所有的语义限制,比如可访问性(第11章),都应该被满足。 ]
[例: 结构X { X(INT); X(const X&); X(); }; X f(X); void g() { X a(1); X b = f(X(2)); a = f(a); }
在这里,一个实现可能使用一个临时的构造X(2),然后用X的copy-constructor传递给f()。 或者,X(2)可能会在用于保存参数的空间中构build。 另外,在使用X的copyconstructor将临时文件复制到b之前,临时文件可能用于保存f(X(2))的结果; 或者,f()的结果可能在b中构造。 另一方面,expression式a = f(a)需要临时参数a或者f(a)的结果来避免a的不希望的混叠。 ]
[最终标准报价]
从本质上说,上面的文字说,你可以在初始化情况下依靠RVO,但不能在分配情况下。 原因是,当你初始化一个对象的时候,你没有办法把它初始化为对象本身(这就是为什么你永远不会在拷贝构造函数中做自检的原因),但是当你一个任务,它可以。
没有任何关于你的代码的内容,它固有地禁止RVO – 但是如果你确实需要的话,阅读你的编译器文档以确保你真的可以依赖它。
我同意duffymo。 您应该首先制作一个可以理解的工作应用程序,然后在有需要时进行攻击优化。 正是在这一点上,你将有一个主要的瓶颈,并将能够更有效地pipe理你的时间,在一个更快的应用程序的想法。
我同意@duffymo。 在进行测量之前不要进行优化,在进行微观优化时,这是双重的。 总是: 在你优化之前和之后测量,看看你是否真的改变了事情。
返回string,在性能方面没有那么大的损失,但是它肯定会在以后减轻你的工作量。
另外,你可以总是内联函数,但大多数优化器将修复它。
如果你传递一个被引用的string,并且你使用这个string,你不需要返回任何东西。 ;)