标签:io os 使用 ar for sp 问题 代码 on
在C++11中,由于右值引用的引入,常为人所诟病std::string的性能问题得到了很大的改善。另外一方面,我们也可以看到新语言为std::string类增加了很多新的api。比较引人注意的就是std::string的成员函数stoi系列,以及std::to_string全局函数。这两种API虽然很不起眼,却为C++11的格式化输出(formatted I/O)增加了一种实用的手段。我们可以依序会议一下C,C++98,C++11中我们是如何处理atoi/itoa的问题的:
在C时代,通常我们遇到atoi(字符串到数值转换)的问题的时候我们会使用中的atoi函数:
int num = atoi(cstr);
这里的cstr通常为char或者const char类型的字符串。函数返回的结果则是该字符串所表示的一个十进制的integer。函数的整个效果则等同于中的另外一个函数strtol:
int num = strtol(cstr, NULL, 10);
相比于atoi,strtol多了最后一个参数"radix"表明函数采用的是几进制(这个进制数可以从2到34,这个数值范围的原因显而易见)。除去strtol会在出错时设置全局的errno外,其效果与atoi系列中的atol则几乎是完全等同的。
而C时代解决itoa(数值到字符串的转换)的时候,则采用了sprintf函数:
int myint;
char buf[SIZE];
sprintf(buf, “my data is %d”, myint);
这里字符的输出控制交给了”%d"这样的特殊字符。通过特殊字符以及变长参数的配合(sprintf是变长参数函数),我们获得预期的formatted I/O的输出。
这里我们可以看到C中对atoi/itoa的处理的特点,基本可以归纳如下:
到了C++98时代,atoi/itoa可以使用新的C++标准库来完成。具体地就是使用C++的流(stream)模板类。值得注意的是,在C++98代码中,虽然字符串的存储使用字符串数组也是完全可以的,但在C++代码中使用std::string类型,内存可以自行有效地管理,而且成员函数可以抛出异常,所以更适用于C++代码。而关于std::string类型的流模板类型就是std::stringstream。通过全局重载的operator «以及operator »,std::stringstream可以很轻松地完成atoi或者是itoa的任务,比如:
ostringstream oss;
oss « 15 « " is int, " « 3.14f « " is float.” « endl;
cout « oss.str();
oss就是一个字符串流对象,可以用于itoa的工作。而
istringstream iss(“12 14.1f”);
int a;
float b;
iss » a » b;
cout « a « " " « b « endl;
上面代码中的iss字符串流对象,则可用作atoi。
从设计上讲,std::stringstream算得上是一种好的设计。这是由于使用std::stringstream的代码看起来非常地直观。而且由于其来自于C++库,程序员通常也不太关心是否会有exception抛出–因为如果代码没有try-catch block的话,exception一旦抛出,程序就会直接直接终止(调用std::terminate)。这种解决出错的方式对于程序员来说更为爽快,因为程序在问题点终止,就很容易找到出问题的代码位置。而C时代的atoi/itoa,如同我们讲到的,需要程序员关注异常,如果漏过处理异常之后(其实这很常见),程序可能带病运行。当然,由于stringstream总是"附着"于一个内存可以自行管理的string对象,所以程序员通常也不必担心任何的内存分配问题。
从设计角度出发看,std::stringstream几乎无可挑剔。但在实际使用中,如我们在上面提到的,很多人还是愿意使用C中的处理方法来完成atoi/itoa。这大概有两方面的原因:
到了C++11中,标准委员会可能是注意到这种"简单比完备"更重要的情况,于是在C++11中,标准增加了全局函数std::to_string,以及std::stoi/stol/stoll等等函数。(最初的paper称之为simple numeric access,N1982)其用法非常简单:
string s;
s += to_string(12) + " is int, “;
s += to_string(3.14f) + " is float.“;
cout « s « endl;
这里的to_string会根据参数的类型完成相应类型地转换。而:
string s(“12”);
int i = stoi(s);
cout « i « endl;
这样的代码则可以顺利完成atoi的任务。由于其是C++11引入的函数,所以具备C所不具备的所有的C++库代码特征:根据类型的处理,抛出异常,以及自动内存管理。
可以看到,std::to_string在实际使用中可能会涉及一些字符串的连结。如我们在文章一开始提到的,C++98中字符串连结一直是C++语言被诟病性能低于C的一个重要方面。而这在C++11引入了右值引用后得到了很大的缓解。因此此时std::to_string这样的函数的实用性就大大增强了。不过std::to_string并不是itoa的一种终极方式。以浮点数为例,to_string甚至连浮点数小数位显示控制这样基本的控制功能都不具备,因此其最大地特点还是突出在其易用性上。C++程序员不必定义一个std::stringstream对象就可以完成安全有效且不必关心任何内存的itoa工作。
而std::stoi/stol/stoll…系列更是简单到只能完成一个数值的转换,比起总是返回std::stringstream &的operator »比起来功能性就差很远了。后者能在一行代码中转化出多个数值。但前者最大地特点仍然突出在易用性上,不必"附着"一个std::stringstream类型。这对很多无需复杂atoi的程序而言也就足够了。
标签:io os 使用 ar for sp 问题 代码 on
原文地址:http://my.oschina.net/u/1864567/blog/316054