字符串接受接口应该是什么样子? [英] How string accepting interface should look like?

查看:128
本文介绍了字符串接受接口应该是什么样子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是这个问题的后续追踪。假设我写了一个接受或返回一个常量字符串的C ++接口。我可以使用const char *以零结束的字符串:

This is a follow up of this question. Suppose I write a C++ interface that accepts or returns a const string. I can use a const char* zero-terminated string:

void f(const char* str); // (1)

另一种方法是使用std :: string:

The other way would be to use an std::string:

void f(const string& str); // (2)

也可以写一个重载并接受两者:

It's also possible to write an overload and accept both:

void f(const char* str); // (3)
void f(const string& str);

或者甚至是与boost字符串算法结合使用的模板:

Or even a template in conjunction with boost string algorithms:

template<class Range> void f(const Range& str); // (4)

我的想法是:


  • (1)不是C ++ ish,并且在后续操作可能需要知道字符串长度时可能效率较低。

  • 因为现在 f(long very long C string); 调用std :: string的构造,涉及堆分配。如果 f 使用那个字符串,只是将它传递给一个需要C字符串(如fopen)的底层接口,那么它只是浪费资源。

  • (3)导致代码重复。虽然一个 f 可以调用另一个取决于什么是最有效的实现。但是我们不能基于返回类型重载,例如在std :: exception :: what()的情况下返回一个const char *。

  • (4)单独的编译,可能会导致更大的代码膨胀。

  • 根据实现需要在(1)和(2)之间进行选择,可以将实现细节泄露到界面。

  • (1) is not C++ish and may be less efficient when subsequent operations may need to know the string length.
  • (2) is bad because now f("long very long C string"); invokes a construction of std::string which involves a heap allocation. If f uses that string just to pass it to some low-level interface that expects a C-string (like fopen) then it is just a waste of resources.
  • (3) causes code duplication. Although one f can call the other depending on what is the most efficient implementation. However we can't overload based on return type, like in case of std::exception::what() that returns a const char*.
  • (4) doesn't work with separate compilation and may cause even larger code bloat.
  • Choosing between (1) and (2) based on what's needed by the implementation is, well, leaking an implementation detail to the interface.

问题是:什么是优先方式?有没有一条我可以遵循的指引?

The question is: what is the preffered way? Is there any single guideline I can follow? What's your experience?

编辑:还有第五个选项:

void f(boost::iterator_range<const char*> str); // (5)

字符串对象)和(2)(字符串的大小显式地传递给函数)。

which has the pros of (1) (doesn't need to construct a string object) and (2) (the size of the string is explicitly passed to the function).

推荐答案

我会用最简单的,经常是 const char * 。这适用于具有零成本的字符串文本,并且从存储在 std:string 中的内容中检索 const char * 非常低的成本。

For taking a parameter I would go with whatever is simplest and often that is const char*. This works with string literals with zero cost and retrieving a const char* from something stored in a std:string is typically very low cost as well.

我个人不会打扰过载。除了最简单的情况,你会想要合并到两个代码路径,并在一个点调用另一个,或者两者都调用一个公共函数。可以说,拥有过载隐藏了一个是否转换为另一个和哪个路径有更高的成本。

Personally, I wouldn't bother with the overload. In all but the simplest cases you will want to merge to two code paths and have one call the other at some point or both call a common function. It could be argued that having the overload hides whether one is converted to the other or not and which path has a higher cost.

只有当我真的想使用 const 函数中的 std :: string 接口的特性我会有 const std :: string& ; 在接口本身,我不确定只是使用 size()是足够的调整。

Only if I actually wanted to use const features of the std::string interface inside the function would I have const std::string& in the interface itself and I'm not sure that just using size() would be enough of a justification.

在许多项目中,不管是好是坏,经常使用替代字符串类。其中许多,如 std :: string 可以方便地访问零终止的 const char * ;转换为 std :: string 需要一个副本。在接口中需要一个 const std :: string& ,即使函数的内部函数不需要指定存储策略,也需要一个存储策略。我认为这是不希望的,就像采取 const shared_ptr< X>& 规定存储策略,而采取 X& ,如果可能,允许调用者使用任何存储策略为一个传递的对象。

In many projects, for better or worse, alternative string classes are often used. Many of these, like std::string give cheap access to a zero-terminated const char*; converting to a std::string requires a copy. Requiring a const std::string& in the interface is dictating a storage strategy even when the internals of the function don't need to specify this. I consider it this to be undesirable, much like taking a const shared_ptr<X>& dictates a storage strategy whereas taking X&, if possible, allows the caller to use any storage strategy for a passed object.

const char * code>是纯粹从接口的角度来看,它不强制非nullness(虽然偶尔地一个空参数和一个空字符串之间的差异在一些接口中使用 - 这不能用 std :: string ),并且 const char * 可能只是一个字符的地址。但在实践中,使用 const char * 来传递一个字符串是非常普遍的,我认为引用这个作为一个负面的是一个相当琐碎的问题。其他问题,例如接口文档中指定的字符的编码(适用于 std :: string const char * )更重要,并可能导致更多的工作。

The disadvantages of a const char* are that, purely from an interface standpoint, it doesn't enforce non-nullness (although very occasionally the difference betweem a null parameter and an empty string is used in some interfaces - this can't be done with std::string), and a const char* might be the address of just a single character. In practice, though, the use of a const char* to pass a string is so prevalent that I would consider citing this as a negative to be a fairly trivial concern. Other concerns, such as whether the encoding of the characters specified in the interface documentation (applies to both std::string and const char*) are much more important and likely to cause more work.

这篇关于字符串接受接口应该是什么样子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆