我们可以从std :: string的c_str()获得什么性能?总是恒定的时间?


13

我最近一直在做一些必要的优化。我一直在做的一件事是更改一些ostringstreams-> sprintfs。我正在将一堆std :: strings冲刺到ac样式数组,ala

char foo[500];
sprintf(foo, "%s+%s", str1.c_str(), str2.c_str());

事实证明,Microsoft的std :: string :: c_str()实现在恒定时间内运行(它只返回一个内部指针)。看来libstdc ++也是一样。我意识到std不能保证c_str,但是很难想象另一种方式。例如,如果他们将其复制到内存中,要么不得不为缓冲区分配内存(将其留给调用方销毁,而不是STL合同的一部分),要么必须将其复制到内部静态对象中。缓冲区(可能不是线程安全的,并且您无法保证其寿命)。因此,仅返回指向内部维护的以null终止的字符串的指针似乎是唯一可行的解​​决方案。

Answers:


9

如果我还记得的话,该标准允许string::c_str()返回几乎所有满足的条件:

  • 存储空间足以容纳字符串和终止符的内容 NULL
  • string调用给定对象的非常量成员之前必须一直有效

因此,实际上,这意味着指向内部存储的指针。因为没有办法从外部跟踪返回的指针的寿命。我认为您的优化可以安全地假设这是(小的)恒定时间。

与此相关的是,如果字符串格式限制了性能;您可能会发现好运会推迟评估,直到绝对需要Boost.Phoenix之类的东西

Boost.Format 我相信内部会推迟格式化,直到需要结果为止,并且您可以重复使用相同的格式对象,而无需重新解析格式字符串,我发现这对于高频日志记录有很大的影响。


2
一个实现可能创建一个新的或辅助的内部缓冲区-足够大以添加空终止符。即使c_str是const方法(或至少具有const重载-我忘记了),但这不会更改逻辑值,因此可能是的原因mutable。这打破指针其他呼叫c_str,但此指针必须指的是同一个逻辑串(所以没有新的理由来重新分配-必须已经有一个空终止),或者必须已到非通话-const方法之间。
Steve314 2011年

如果这确实有效,则c_str调用可能需要O(n)时间进行重新分配和复制。但是,我可能不知道该标准中还有其他规则会阻止这种情况。我认为它的原因-呼叫c_str是不是真的意味着是常见AFAIK,所以它可能不会被认为是重要的,以确保他们快-避免存储的额外字节,以实现通常不需要空终止的string情况下,从来没有使用c_str可能优先。
Steve314 2011年

Boost.Format内部流经内部流,sprintf最终导致相当大的开销。文件说,它比普通的慢约8倍sprintf。如果需要性能和类型安全性,请尝试Boost.Spirit.Karma
Jan Hudec

Boost.Spirit.Karma是提高性能的一个很好的技巧,但请注意,它具有截然不同的方法,很难适应现有的printf样式代码(和编码器)。我一直坚持不懈,Boost.Format因为我们的I / O是异步的。但是一个很大的因素是,我可以说服我的同事们一贯使用它(仍然允许任何类型的ostream<<重载-很好地避开.c_str()争论)Karma性能数字。
rvalue

23

在c ++ 11标准(我正在阅读N 3290版本)中,第21.4.7.1章讨论了c_str()方法:

const charT* c_str() const noexcept; const charT* data() const noexcept;

返回:指针p,使得[0,size()]中每个i的p + i ==&operator。
复杂度:恒定时间。
要求:程序不得更改存储在字符数组中的任何值。

因此,是的:标准保证了恒定的时间复杂度。

我刚刚检查了c ++ 03标准,它没有这样的要求,也没有说明复杂性。


8

从理论上讲,C ++ 03不需要这样做,因此字符串可以是char的数组,其中恰好在调用c_str()时添加了空终止符。这可能需要重新分配(如果内部私有指针声明为,则不违反常量性mutable)。

C ++ 11更严格:它需要时间,因此无法进行重定位,并且数组必须始终足够宽以在末尾存储null。c_str()本身仍然ptr[size()]='\0'可以确保实际存在null。它不会违反数组的常量性,因为范围[0..size())不会更改。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.