在邮件列表中有朋友提出:
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()得到错误的值。
oscar.ken@gmail.com:
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, 0, 2048 * 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% 应当是总体的性能下降。纯粹的内存分配/释放操作,堆上分
配和栈上分配的性能根本不在同一个量级,差距通常在十倍以上。