【问题标题】:When should std::string be used over character arrays?什么时候应该在字符数组上使用 std::string?
【发布时间】:2014-06-16 11:59:12
【问题描述】:

当我设计类接口时,我经常坐下来思考是否应该使用const char*const std::string&另一个半打。

取以下两个函数原型:

void foo(const char* str);
void foo(std::string str);

如果foo 函数要存储一个字符串,我会说第二个是更好的选择,因为它能够传递字符串并在可能的情况下利用移动语义。但是,如果foo只需要读取字符串,const char*的方案会更好吗?

从性能角度来看,不需要创建临时的std::string。但是,使用已经存在的字符串作为参数调用函数看起来很突兀:foo(mystr.c_str())。更糟糕的是,如果以后某个时候需要对阵列进行更高级的操作,或者如果应该存储一个副本,那么就必须更改接口。

所以我的问题是这样的:

是否存在明确定义的(无论是个人的还是其他方面的)约定以规定 std::stringconst char* 何时是更好的选择?此外,在开始一个新项目时,是最好与使用保持一致还是选择最适合当前代码块的那个?

【问题讨论】:

  • 一个简单的规则是:如果你不确定,那么你最好使用std::string
  • 如果您不想创建临时字符串,请使用void foo(const std::string &bar)
  • @RedAlert 调用 foo("hello") 不会导致使用 std::string 变体创建临时对象吗?
  • string 是为字符串设计的, const char * 只适用于常量字符串字面量。对于字符串变量,使用 char * 是禁忌。速度在 99.9% 的情况下都无关紧要,如果您的字符串有 15 个字符,则无论如何都必须将它们存储在某处,没有任何魔法可以让您节省存储空间。按引用传递不会复制数据,如果您一直按值传递参数,那么您做得非常糟糕。
  • 总是更喜欢std::string。它为您节省了以后的麻烦。相信我。

标签: c++ string character-arrays


【解决方案1】:

const char* 是对 C 的回归。我想说,在体面的 C++ 中,它的唯一用途是在 extern "C" API 中。

std::string 有很多优点:

  1. 它提供了一个恒定时间的size() 函数。发现const char* 的长度需要线性时间。

  2. 保证有效。必须检查 const char* 是否为空,并且完全有可能传递不正确的数据 - 数据缺少空终止符。这种情况几乎肯定会导致崩溃或更糟。

  3. 兼容标准算法。

如果您担心必须创建 std::string 来调用函数会影响性能,请考虑采用标准库使用的方法 - 将函数更改为采用一对迭代器。然后,您可以提供一个方便的重载,将 const std::string& 委托给迭代器对。

【讨论】:

  • 我不太担心性能,而是担心整个界面的连贯性。我发现更容易阅读的代码也更容易调试和优化。
  • string 在这里也更好。比较myFunc(const char*)myFunc(string)
  • @DarkWanderer 你的意思是myFunc(std::string)
  • 没有。标题中的using std::string 是必须的。
  • @DarkWanderer No. 在标题中键入using anyNamespaceOrType 是一个非常糟糕的主意,原因我希望我不必解释。推荐这个是误导性的,尤其是像“必须”这样的单方面词。事实上,包括我在内的很多人甚至都不在任何地方打扰using std
【解决方案2】:

只是一些个人经验的笔记。如果您正在开发一个 c++ 项目(根据您添加的标签),请尽可能多地使用提供的std::string。不要试图重新发明所有结构中最基本的,万能的弦。我看到了几个项目,他们重新发明了基本弦乐,然后花了几个月的时间对其进行微调。

如果您的 c++ 项目从您引入 char* 变量的那一刻起,您就会退回到标准 C 函数,例如 strlen()strcpy(仅举两个例子......)。从这一点开始,您的项目开始变得一团糟,手动管理内存分配等......

如果您需要与接受 const char* 作为参数的第三方库进行交互(我想您相信这些库 - 即:您相信他们不会 const_cast 摆脱对穷人做坏事的一贯性string) 您可以使用std::string::c_str()const char* 从您的字符串中取出。

如果您需要与具有接受 char* 的方法的库进行交互,我强烈建议您复制字符串的 c_str() 并将其用作库的传入参数(当然,不要忘记删除额外的副本)。

除了这些额外的点,我只是订阅了 Angew 回复中的所有三点。

【讨论】:

  • 感谢您的建议,真的很有帮助。
  • 这也是我的回答,尤其是“如果你发现自己需要 C 函数,只需使用 std::string”位。
【解决方案3】:

std::string 应该始终是 C++ 中的首选。为避免额外的复制开销,您几乎应该始终将参数作为引用传递,const 引用在任何地方和任何时候都可以。

在这种情况下,您的函数签名会变成这样

void foo(std::string &str);

如果参数是 const 就这样

void foo(const std::string &str);

这个 const 关键字的好处你可以看看here

【讨论】:

  • 不,在 C++11 中,如果你需要复制字符串,你应该通过值而不是 const 引用传递。
  • 另外,有时最好不要通过引用传递内置函数,请参阅stackoverflow.com/questions/5346853/…
  • 是的,它只在可能的地方和时间......因为它提高了 API 的可读性
【解决方案4】:

而不是使用

void foo(std::string str); 

你可以使用

void foo(const std::string& str);

这将相当于

void foo(const char* str);

在使用方面,因为传递引用时没有分配内存。但对于 C++ 中的字符串,我肯定会使用 std::string。对于随机数据或与 C 兼容的接口,我不会。

【讨论】:

  • const std::string& 如果传递了字符串文字(需要创建),则可能需要新数据。 const char* 可以在运行时避免这种分配。
  • 我在使用const std::string& 时遇到的唯一问题是当我知道我需要制作副本时。这就是选择std::string的理由
  • @Ben char[] 在使用字符串字面量调用函数时也会创建。使用char* 没有任何好处
  • @Theolodis 这样做会破坏 c++11 中移动语义的好处。
  • @Theolodis 基本上,如果你知道你要复制它,你应该使用std::string。像foo(some_func_that_returns_a_string()) 这样的调用将通过移动语义将它们的结果直接传递到下一个调用中。在很多情况下,甚至可以省略移动。见stackoverflow.com/questions/3106110/what-is-move-semantics
【解决方案5】:

std::string 比使用 raw char * 更好,你必须管理分配、解除分配和与大小相关的问题,以小心任何溢出、下溢,你没有跨越大小边界。而 std::string 这些都是通过抽象处理的

【讨论】:

    【解决方案6】:

    如果您想更好地处理您的数据(在您的情况下它将是字符串),我会说使用 char *。它将让您更好地访问您的字符串和内存利用率。 但是,如果您不必担心性能和内存管理问题,那么您可以轻松使用 std::string。

    【讨论】:

    • 这对我来说是一个难以接受的立场,因为在大多数情况下,性能和内存管理并不重要,不足以保证令人困惑的代码或潜在的编程错误。
    • 同意...但由编码人员决定他/她如何编写代码[令人困惑或易于理解]。尽管如果我们寻找比内存利用率更大的图景更重要[例如在 n/w 上传输数据]
    【解决方案7】:

    好吧,我想稍微改一下你的问题。您应该询问何时应该使用字符数组而不是 std::string

    这是因为您应该始终使用string,除非您不能使用它。所以你应该使用字符数组而不是string的情况:

    1. 使用支持 C 的 API,因此您无法使用 string
    2. exedll 之间传递数据。不建议在exedll 之间交换具有构造函数和/或析构函数的数据类型

    如果您担心性能,在启用所有优化的编译后string 变得类似于字符数组,在某些情况下可能会提供更好的性能,例如如果您需要获取它包含的字符数。

    关于性能,你总是可以通过引用传递,正如其他答案所提到的,如果你必须传递一个指向字符数组的指针,你可以使用方法c_str()返回const指向第一个字符的指针,如果你必须传递指针(不是const 指针)你可以(但实际上不应该)像这样传递它:&str[0]

    【讨论】:

      猜你喜欢
      • 2017-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-12
      • 1970-01-01
      • 1970-01-01
      • 2019-04-13
      • 2011-03-25
      相关资源
      最近更新 更多