STL中string的初始化问题

在邮件列表中有朋友提出:

1 // 我希望把string赋值10,然后显示
2 string  Buffer;
3 sprintf( Buffer.begin(), " %d " , 10 );
4 MessageBox(NULL,Buffer.begin(),NULL,MB_OK);

建个程序,编译它,是通不过的。原因是Buffer没有初值 ,调用Buffer.begin()返回是NULL ,第三句用MessageBox弹出一个NULL的字符串 ,这是不可取的。

1 // 改正后的程序
2 string  Buffer  =   " a " // 我随便给了个初值
3 sprintf( Buffer.begin(), " %d " , 10 );
4 MessageBox(NULL,Buffer.begin(),NULL,MB_OK);

但是,上面这段程序,可读性能差。别人会想:作者为什么给个"a "而不是"b"呢?

所以我想请教大家:
(1)这问题有没有更好的方法?最好不要MFC,也不用char数 组,因为整个程序中其它地方我都用了string。
(2)STL为什么这么设计?
难道定义Buffer以后,还没有分配空间?如果已经有空间 ,为什么不用Begin()返回首个字符的地址?这样做意义呵在?


解答一:

1 //  这么定义:
2 string  Buffer( 256 ' \0 ' );
3 //  或者
4 string  Buffer;
5 Buffer.reserve( 256 );

解答二:
1 //  1.使用boost:Buffer = boost::lexical_cast<string>(10);
2 //  2.如果不想用boost:
3 #include  < sstream >
4
5 std::stringstream sstr;
6 sstr  <<   10 ;
7 Buffer  =  sstr.str();
8 //  或者:
9 Buffer  =  (std::stringstream()  <<   10 ).str(); 

解答三:
 1   std::vector < char >  buf(buffer_size,  0 );
 2   _snprintf( & buf[ 0 ], buffer_size,  " %d\0 " 10 );
 3    //  赋值给字符串
 4   std:: string  str  =   & buf[ 0 ];
 5   MessageBox(NULL, str.c_str(), NULL, MB_OK);
 6 // 好处:
 7 //     1. 使用std::vector避免手动new/delete
 8 //     2. 使用stl可以充分利用stl的alloc(如stlport的memory pool)
 9 //     3. 使用_snprintf防止溢出
10 //     4. std::string = std::vector(安逸:)

解答四:
1    char  buf[ 32 ];
2   _snprintf(buf,  32 " %d " 10 ); // 或者用itoa(10, buf, 10);
3    string  str  =  buf;

有朋友发现一个错误:
看到一个明显错误的做法: str.reserve(NLEN) 之后直接去 sprintf 。要知道 reserve 只是把 capacity 扩充到 NLEN ,并不会扩充 size 。对于某些标准库实现,这样的做法极端危险,它会破坏 string 的不变式,导致一系列严重问题,比如 str.size() str.length() 得到错误的值。

[email protected]
 1 #ifdef  UNICODE
 2
 3 # define tchar wchar_t
 4 # define tstring std::wstring
 5
 6 #else
 7
 8 # define tchar  char
 9 # define tstring std:: string
10
11 #endif
12 inline tstring FormatString( const  tchar *  fmt, )
13 {
14 static tchar tmp[2048];
15 memset(tmp, 02048 * sizeof(tchar));
16 va_list args;
17 va_start(args, fmt);
18 int re = _vsntprintf(tmp, 2048, fmt, args);
19 va_end(args);
20 return tstring(tmp);
21}

22
23 //  如果2048不够用,可以改造一个template版本

千里马肝:
如果这样
那不如直接使用boost::format导出一个stream的string,更安逸(当然会慢一些)
 
PS,对于FormatString为了保证format出来的是一个string,每次memset,个人认为无大必要,不如自动在formatstring的最后每次自动加上\
0   (XD)

如果我没有记错的话
_snprintf是不会自动补\0的
而sprintf会
所以要么char buf[
32 =   {0} ,要么_snprintf(  " %d\0 " )
另外vector的使用是为了配合“不定长buf”而存在,并非buf[
32 ]的替代品

Jiong Tu:
你搞错了,不补0的是strncpy,不是snprintf

吴咏炜:
用 STL 的最大好处就是空间大小可以自动增长,不会发生缓冲区溢出(安全问
题)。否则,又何必付出缓慢的堆上分配的代价呢?——除非要把结果传回去,那还
有意义;但最初苏益彧提出的问题中并不存在这样的需求。

另外顺便提一下,如果栈上分配内存大小不固定,也不一定就要改用堆上分配。
C99 支持数组大小运行时决定(而非 C89
/ C ++ 98  的编译时决定),而(不支持
C99 的)大部分 C
/ C ++  编译器也都支持一个非标准的 alloca 函数用于进行栈上
分配。这个函数通常由编译器内联实现,需要效率的场合会用得上。

另外,你测出的 
50 %  应当是总体的性能下降。纯粹的内存分配 / 释放操作,堆上分
配和栈上分配的性能根本不在同一个量级,差距通常在十倍以上。

你可能感兴趣的:(STL中string的初始化问题)