这是对这个问题的跟进.假设我编写了一个接受或返回const字符串的C++接口.我可以使用const char*以零结尾的字符串:
void f(const char* str); // (1)
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用std :: string:
void f(const string& str); // (2)
Run Code Online (Sandbox Code Playgroud)
也可以写一个重载并同时接受:
void f(const char* str); // (3)
void f(const string& str);
Run Code Online (Sandbox Code Playgroud)
甚至是与boost字符串算法结合使用的模板:
template<class Range> void f(const Range& str); // (4)
Run Code Online (Sandbox Code Playgroud)
我的想法是:
f("long very long C string");调用std :: string的构造,其涉及堆分配.如果f使用该字符串只是为了将它传递给一个需要C字符串的低级接口(如fopen)那么它只是浪费资源.f可以根据什么是最有效的实现来调用另一个.但是我们不能基于返回类型重载,就像std :: exception :: what()返回const char*一样.问题是:什么是优先方式?我可以遵循任何单一指南吗?你有什么经历?
编辑:还有第五个选项:
void f(boost::iterator_range<const char*> str); // (5)
Run Code Online (Sandbox Code Playgroud)
它具有(1)的优点(不需要构造字符串对象)和(2)(字符串的大小显式传递给函数).
如果你正在处理一个纯C++代码库,那么我会选择#2,而不用担心函数的调用者在出现问题之前不会将它与std :: string一起使用.一如既往,除非出现问题,否则不要过于担心优化问题.使您的代码清洁,易于阅读,并且易于扩展.
为了获取参数,我会选择最简单且通常是的const char*。这适用于零成本的字符串文字,并且const char*从存储在 a 中的内容中检索 astd:string的成本通常也非常低。
就我个人而言,我不会为超载而烦恼。除了最简单的情况外,在所有情况下,您都希望合并到两个代码路径,并让一个代码路径在某个时刻调用另一个代码路径,或者两者都调用一个公共函数。可能有人会说,过载隐藏了一条路径是否转换为另一条路径以及哪条路径的成本更高。
只有当我真的想在函数内部使用接口const的功能时std::string,我才会const std::string&在接口本身中使用它,并且我不确定仅仅使用size()就足够了。
在许多项目中,无论好坏,经常使用替代字符串类。其中许多,例如std::string提供对零终止的廉价访问const char*;转换为 astd::string需要副本。const std::string&即使函数内部不需要指定存储策略,在接口中要求a 也是指定存储策略。我认为这是不可取的,就像采取 aconst shared_ptr<X>&指示存储策略,而采取X&,如果可能的话,允许调用者对传递的对象使用任何存储策略。
a 的缺点const char*是,纯粹从接口的角度来看,它不强制非空性(尽管在某些接口中偶尔会使用 null 参数和空字符串之间的差异 - 这不能用 来完成std::string), aconst char*可能只是一个字符的地址。但在实践中,使用 aconst char*传递字符串是如此普遍,以至于我认为将此作为否定引用是一个相当微不足道的问题。其他问题,例如接口文档中指定的字符编码是否(适用于 和std::string)const char*更为重要,并且可能会导致更多工作。
| 归档时间: |
|
| 查看次数: |
1421 次 |
| 最近记录: |