编辑 2012-04-11
rve非常正确地评论了 lexical_cast 的性能,并提供了一个链接:
http://www.boost.org/doc/libs/1_49_0/doc/html/boost_lexical_cast/performance.html
我现在无法升级 1.49,但我确实记得在旧版本上让我的代码更快。所以我猜:
- 以下答案仍然有效(如果仅用于学习目的)
- 可能在两个版本之间的某个地方引入了优化(我会搜索)
- 这意味着boost仍然越来越好
原始答案
只是为了添加有关 Barry's 和 Motti 出色答案的信息:
一些背景
请记住,Boost 是由这个星球上最优秀的 C++ 开发人员编写的,并由同样优秀的开发人员进行审查。如果lexical_cast
错了,有人会用批评或代码入侵图书馆。
我猜你错过了lexical_cast
's 的真正价值点......
比较苹果和橘子。
在 Java 中,您将整数转换为 Java 字符串。您会注意到我不是在谈论字符数组或用户定义的字符串。您也会注意到,我不是在谈论您的用户定义整数。我说的是严格的 Java 整数和严格的 Java 字符串。
在 Python 中,您或多或少都在做同样的事情。
正如其他帖子所说,本质上,您使用的是 Java 和 Python 等价物sprintf
(或不太标准的itoa
)。
在 C++ 中,您使用的是非常强大的强制转换。在原始速度性能方面并不强大(如果您想要速度,也许sprintf
会更适合),但在可扩展性方面强大。
比较苹果。
如果要比较 JavaInteger.toString
方法,则应将其与 Csprintf
或 C++ostream
工具进行比较。
C++ 流解决方案将比 (在我的 g++ 上)快 6 倍lexical_cast
,而且可扩展性要小得多:
inline void toString(const int value, std::string & output)
{
// The largest 32-bit integer is 4294967295, that is 10 chars
// On the safe side, add 1 for sign, and 1 for trailing zero
char buffer[12] ;
sprintf(buffer, "%i", value) ;
output = buffer ;
}
Csprintf
解决方案将比(在我的 g++ 上)快 8 倍,lexical_cast
但安全性要低得多:
inline void toString(const int value, char * output)
{
sprintf(output, "%i", value) ;
}
两种解决方案都与您的 Java 解决方案一样快或更快(根据您的数据)。
比较橘子。
如果要比较 C++ lexical_cast
,则应将其与以下 Java 伪代码进行比较:
Source s ;
Target t = Target.fromString(Source(s).toString()) ;
boolean
Source 和 Target 可以是您想要的任何类型,包括像or这样的内置类型int
,这在 C++ 中是可能的,因为模板。
可扩展性?这是脏话吗?
不,但它有一个众所周知的成本:当由同一编码人员编写时,针对特定问题的通用解决方案通常比针对特定问题编写的特定解决方案要慢。
在当前情况下,从幼稚的观点来看,lexical_cast
将使用流工具将类型A
转换为字符串流,然后从该字符串流转换为类型B
。
这意味着只要您的对象可以输出到流中,并从流中输入,您就可以使用lexical_cast
它,而无需触及任何一行代码。
那么,有什么用途lexical_cast
呢?
词法转换的主要用途是:
- 易于使用(嘿,一个适用于所有有价值的 C++ 转换!)
- 将它与模板繁重的代码相结合,您的类型是参数化的,因此您不想处理细节,也不想知道类型。
- 如果您有基本的模板知识,仍然可能相对有效,我将在下面演示
第 2 点在这里非常重要,因为这意味着我们只有一个接口/函数可以将一个类型的值转换为另一个类型的相等或相似的值。
这是您错过的真正要点,这是在性能方面付出代价的要点。
但它是如此slooooooowwww!
如果您想要原始速度性能,请记住您正在处理 C++,并且您有很多工具可以有效地处理转换,并且仍然保持lexical_cast
易于使用的特性。
我花了几分钟查看 lexical_cast 源代码,并提出了一个可行的解决方案。将以下代码添加到您的 C++ 代码中:
#ifdef SPECIALIZE_BOOST_LEXICAL_CAST_FOR_STRING_AND_INT
namespace boost
{
template<>
std::string lexical_cast<std::string, int>(const int &arg)
{
// The largest 32-bit integer is 4294967295, that is 10 chars
// On the safe side, add 1 for sign, and 1 for trailing zero
char buffer[12] ;
sprintf(buffer, "%i", arg) ;
return buffer ;
}
}
#endif
通过为字符串和整数启用 lexical_cast 的这种特殊化(通过定义宏SPECIALIZE_BOOST_LEXICAL_CAST_FOR_STRING_AND_INT
),我的代码在我的 g++ 编译器上运行速度提高了 5 倍,这意味着根据您的数据,它的性能应该与 Java 相似。
我花了 10 分钟查看 boost 代码,并编写了一个远程高效且正确的 32 位版本。通过一些工作,它可能会更快更安全(std::string
例如,如果我们可以直接写入内部缓冲区,我们可以避免使用临时外部缓冲区)。