如何在没有副本的情况下从字符串流中获取字符?

时间:2015-02-22 20:48:09

标签: c++ c++11 stringstream

在不使用boost的情况下从字符串流中提取一组字符的正确c ++ 11方法是什么?

如果可能的话,我想在没有复制的情况下这样做,因为使用它的地方是关键数据循环。但是,似乎std :: string不允许直接访问数据。

例如,下面的代码执行字符串流中的子字符串复制:

inline std::string left(std::stringstream ss, uint32_t count) {
    char* buffer = new char[count];
    ss.get(buffer, count);
    std::string str(buffer);  // Second copy performed here
    delete buffer;
    return str;
}
  1. 我是否应该根据c ++ 11使用char * buffer?
  2. 如何绕过第二份副本?
  3. 我的理解是矢量初始化每个角色,所以我想避免这种情况。

    此外,这需要传递给一个接受const char *的函数,所以现在运行后我被迫做一个.c_str()。这也是副本吗?

    能够传回一个const char *会很好,但这似乎违背了#34;正确的#34; c ++ 11风格。

    为了理解我想要做什么,这里是"有效"我想用它来做什么:

    fprintf( stderr, "Data: [%s]...", left(ststream, 255) );
    

    但是c ++ 11强迫:

    fprintf( stderr, "Data: [%s]...", left(str_data, 255).c_str() );
    

    我在这里制作了多少份该字符串?

    如何将其从字符串流中仅减少到一个副本?

4 个答案:

答案 0 :(得分:8)

您可以使用此链接中描述的内容:How to create a std::string directly from a char* array without copying?

基本上,创建一个字符串,使用传递给函数的大小调用字符串上的resize()方法,然后将指针传递给stringstring.get()方法的字符串的第一个字符。您最终只能获得一份副本。

inline std::string left(std::stringstream& ss, uint32_t count) {
    std::string str;
    str.resize(count);
    ss.get(&str[0], count);
    return str;
}

答案 1 :(得分:2)

我的建议:

  1. 通过为其提供尺寸来创建要返回的std::string

  2. stringstream逐一阅读字符,并在std::string中设置值。

  3. 这是函数的样子:

    inline std::string left(std::stringstream ss, uint32_t count) {
        std::string str(count+1, '\0');
        for (uint32_t i = 0; i < count; ++i )
        {
            int c = ss.getc();
            if ( c != EOF )
            {
               str[i] = c;
            }
            else
            {
               break;
            }
        }
        return str;
    }
    

答案 2 :(得分:2)

R Sahu,我喜欢这个!现在很明显我看到它完成了。 ;-)

我确实有一个mod(以及传递了我在我的版本中实际拥有的stream_ptr流):

在初始化程序中,您正在填充空值。你只需填写最后一个,所以我建议调整一下:

inline std::string left(std::shared_ptr<std::stringstream> ss, uint32_t count) {
    std::string str;
    str.reserve(count + 1);
    uint32_t i;
    for(i = 0; i < count; ++i) {
        int c = ss->get();
        if(c != EOF) {
            str[i] = c;
        } else {
            break;
        }
    }
    str[i] = '\0';
    return str;
}

现在,只在单个字符上使用空值进行初始化。

谢谢R Sahu!

答案 3 :(得分:0)

如果此函数的目的仅仅是传递给fprintf或另一个C风格的流,那么您可以通过执行以下操作来完全避免分配:

void left(FILE *out, std::stringstream &in, size_t count)
{
    in.seekg(0);
    char ch;
    while ( count-- && in.get(ch) )
        fputc(out, static_cast<unsigned char>(ch));
}

用法:

fprintf( stderr, "Data: [" );
left(stderr, stream, 255);
fprintf( stderr, "] ...\n");

请记住,如果您稍后尝试在字符串流上使用流读取功能,则需要另一个seekg;如果这个速度与涉及str()的选项相同或更慢,那就不会让我感到惊讶。