std :: string.resize()和std :: string.length() [英] std::string.resize() and std::string.length()

查看:803
本文介绍了std :: string.resize()和std :: string.length()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm relatively new to C++ and I'm still getting to grips with the C++ Standard Library. To help transition from C, I want to format a std::string using printf-style formatters. I realise stringstream is a more type-safe approach, but I find myself finding printf-style much easier to read and deal with (at least, for the time being). This is my function:


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;
}

我不确定的一些事情是:

This works, kinda. A few things that I am not sure about are:


  1. 我需要为空终止符腾出空间,还是这不必要? / li>
  2. capacity()正确的函数要调用吗?我一直认为 length()将返回0,因为字符串中的第一个字符是'\0'

  1. Do I need to make room for a null terminator, or is this unnecessary?
  2. Is capacity() the right function to call here? I keep thinking length() would return 0 since the first character in the string is a '\0'.

偶尔在将此字符串的内容写入套接字时(使用 c_str $ c>和 length()),我有空字节弹出接收端,这是一个悲伤,但他们似乎不一致。如果我根本不使用这个函数,则不会出现空字节。

Occasionally while writing this string's contents to a socket (using its c_str() and length()), I have null bytes popping up on the receiving end, which is causing a bit of grief, but they seem to appear inconsistently. If I don't use this function at all, no null bytes appear.

推荐答案

这里)不能保证由 std :: string 管理的内部存储器缓冲区将是连续的,或者 .c_str()方法返回一个指向内部数据表示的指针(该实现允许为该操作生成一个连续的只读块,并返回一个指针指向实际内部数据的指针可以用 .data()成员方法,但是注意它也返回一个常量指针:ie它不是为你修改内容缓冲区返回 .data()它不一定是null终止,实现只需要保证当终止 c_str()在调用 .data() .c_str()的实现中,实现可以添加<$ c $

With the current standard (the upcomming standard differs here) there is no guarantee that the internal memory buffer managed by the std::string will be contiguous, or that the .c_str() method returns a pointer to the internal data representation (the implementation is allowed to generate a contiguous read-only block for that operation and return a pointer into it. A pointer to the actual internal data can be retrieved with the .data() member method, but note that it also returns a constant pointer: i.e. it is not intended for you to modify the contents. The buffer return by .data() it is not necessarily null terminated, the implementation only needs to guarantee the null termination when c_str() is called, so even in implementations where .data() and .c_str() are called, the implementation can add the \0 to the end of the buffer when the latter is called.

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

The standard intended to allow rope implementations, so in principle it is unsafe to do what you are trying, and from the point of view of the standard you should use an intermediate std::vector (guaranteed contiguity, and there is a guarantee that &myvector[0] is a pointer to the first allocated block of the real buffer).

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

In all implementations I know of, the internal memory handled by std::string is actually a contiguous buffer and using .data() is undefined behavior (writting to a constant variable) but even if incorrect it might work (I would avoid it). You should use other libraries that are designed for this purpose, like boost::format.

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

About the null termination. If you finally decide to follow the path of the undefined... you would need to allocate extra space for the null terminator, since the library will write it into the buffer. Now, the problem is that unlike C-style strings, std::strings can hold null pointers internally, so you will have to resize the string down to fit the largest contiguous block of memory from the beginning that contains no \0. That is probably the issue you are finding with spurious null characters. This means that the bad approach of using vsnprintf(or the family) has to be followed by str.resize( strlen( str.c_str() ) ) to discard all contents of the string after the first \0.

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

Overall, I would advice against this approach, and insist in either getting used to the C++ way of formatting, using third party libraries (boost is third party, but it is also the most standard non-standard library), using vectors or managing memory like in C... but that last option should be avoided like the plague.

// 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] );

这篇关于std :: string.resize()和std :: string.length()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆