std :: string.resize()和std :: string.length()

dre*_*lax 2 c++ string printf c++-standard-library

我对C++比较陌生,我仍然在掌握C++标准库.为了帮助从C转换,我想格式化一个std::string使用printf风格的格式化程序.我意识到这stringstream是一种更加类型安全的方法,但我发现自己发现printf风格更容易阅读和处理(至少,暂时).这是我的功能:


using namespace std;

string formatStdString(const string &format, ...)
{
    va_list va;
    string output;
    size_t needed;
    size_t used;

    va_start(va, format);
    needed = vsnprintf(&output[0], 0, format.c_str(), va);
    output.resize(needed + 1); // for null terminator??
    va_end(va);    

    va_start(va, format);
    used = vsnprintf(&output[0], output.capacity(), format.c_str(), va);
    // assert(used == needed);
    va_end(va);

    return output;
}
Run Code Online (Sandbox Code Playgroud)

这很有效.我不确定的一些事情是:

  1. 我是否需要为空终止符腾出空间,或者这是不必要的?
  2. capacity()在这里打电话是正确的功能吗?我一直在想length(),因为字符串中的第一个字符是a,所以会返回0 '\0'.

偶尔在将这个字符串的内容写入套接字(使用它的c_str()length())时,我在接收端弹出了空字节,这引起了一些悲伤,但它们看起来似乎不一致.如果我根本不使用此函数,则不会出现空字节.

Dav*_*eas 12

使用当前标准(此处的升级标准不同),不能保证由其管理的内部存储器缓冲区std::string将是连续的,或者该.c_str()方法返回指向内部数据表示的指针(允许实现生成连续的读取 -只有该操作的块并返回一个指针.指向实际内部数据的指针可以使用.data()成员方法检索,但请注意它也返回一个常量指针:即它不是为了你修改内容.由.data()它返回的缓冲区不一定是null终止的,实现只需要在c_str()调用时保证null终止,所以即使在实现where .data().c_str()被调用时,实现可以在\0调用后者时将其添加到缓冲区的末尾.

标准旨在允许绳索实现,所以原则上做你正在尝试的东西是不安全的,并且从标准的角度来看你应该使用中间std::vector(保证连续性,并且有一个保证&myvector[0]是指向第一个分配的实际缓冲区块).

在我所知道的所有实现中,处理的内部存储器std::string实际上是一个连续的缓冲区,并且使用.data()未定义的行为(写入常量变量),但即使它不正确也可以工作(我会避免它).您应该使用为此目的而设计的其他库,例如boost::format.

关于null终止.如果你最终决定遵循未定义的路径......你需要为null终止符分配额外的空间,因为库会将它写入缓冲区.现在,问题在于,与C风格的字符串不同,std::strings可以在内部保存空指针,因此您必须向下调整字符串的大小以适应从包含否的开头的最大连续内存块\0.这可能是您发现虚假空字符的问题.这意味着vsnprintf必须遵循使用(或族)的不良方法,str.resize( strlen( str.c_str() ) )在第一个之后丢弃字符串的所有内容\0.

总的来说,我会反对这种方法,并坚持要么习惯了C++的格式化方式,使用第三方库(boost是第三方,但它也是最标准的非标准库),使用向量或管理内存就像在C ......但最后的选择应该像瘟疫一样避免.

// A safe way in C++ of using vsnprintf:
std::vector<char> tmp( 1000 ); // expected maximum size
vsnprintf( &tmp[0], tmp.size(), "Hi %s", name.c_str() ); // assuming name to be a string
std::string salute( &tmp[0] );
Run Code Online (Sandbox Code Playgroud)

  • 请注意,最终标准C++ 11也保证所有`std :: basic_string`都以空值终止.从技术上讲,它们由`CharT()`(其中`CharT`是字符类型)终止,当与`char`一起使用时,它将产生空终止符.所以`.data()`将返回一个以null结尾的字符串,你可以*依赖于那里的终结符.另请注意,C++ 11规范说更改终结符将导致未定义的行为. (2认同)

sbi*_*sbi 5

boost::format如果您喜欢使用printf()流,请使用.

编辑:为了说清楚,实际上我完全赞同艾伦,他说你应该使用流.

  • 在我作为c ++开发人员的整个职业生涯中,Boost还没有为我生产一杯可饮用的咖啡:) (3认同)