【问题标题】:copying a fixed length of data from an std::istream to a string将固定长度的数据从 std::istream 复制到字符串
【发布时间】:2014-11-21 12:32:50
【问题描述】:

我想将固定长度的数据从 std::istream 复制到字符串:

std::istream & operator >> ( std::istream & is, LogMsg & msg )
{
    // read in 4 bytes - a uint32_t that describes the number of bytes in message:
    // next, read the message bytes into the LogMsg

    typedef std::istream_iterator<unsigned char> Iter;

    Iter            i (is);
    uint32_t        nSize   = 0;
    std::string &   sMsg    = msg.MsgRef();

    is >> nSize;
    sMsg.reserve(nSize);

    std::copy(
        i.begin(), i.begin() + nSize,
        std::back_inserter(sMsg)
    );

    return is;
}

我不能使用这个解决方案,因为迭代器上的 std::istream_iterator::begin() 函数只有 c++11(我被 gcc 4.4.7 限制为 -std=gnu++0x

那么,如何将输入流中固定长度的数据复制到字符串中呢?

我最初看的是std::istream::read,它似乎很合适——它有以下语法

is.read (buffer,length);

但我不认为你可以读入字符串的内部缓冲区,我想避免复制到临时缓冲区。我可以以某种方式使用流缓冲区吗?

【问题讨论】:

  • AFAIK 在 C++11 中没有 begin()/end() 函数用于 istream_iterator
  • 流是数据流,而不是容器。

标签: c++ iostream


【解决方案1】:

显而易见的解决方案是std::copy_n:

std::copy_n( std::istreambuf_iterator<char>( is ), size, std::back_inserter( msg ) );

这只有在你可以确定字符在那里时才有效, 然而。如果您在尝试读取文件时遇到文件结尾 字符,未定义的行为随之而来。这意味着虽然它是 一个明显的解决方案,它可能不是一个好的解决方案。

然而,在 C++11 中,正式的,在早期的实现中,在 练习,可以读入内部缓冲区。你必须确保 字符串有足够的空间:

msg.resize( size );
is.read( &msg[0], msg.size() );

(由于某种原因,没有非常量版本的 std::string::data(),尽管保证了潜在的连续性 C++11.)

【讨论】:

    【解决方案2】:

    您可以复制到字符串的内部缓冲区,只要确保它的大小正确:

    sMsg.resize(nSize);
    is.read(&sMsg[0], nSize);
    

    它比begin() 的解决方案效率低,因为您必须对一大堆立即覆盖的数据进行零初始化。但它会在 C++11 之前工作。

    【讨论】:

    • 技术上这是 UB pre-C++11。
    • 不严格保证连续性。尽管在实践中它有点是。实际上,从 GCC 4.9 开始,我认为他们仍在使用带有 COW 的旧实现,这在 C++11 中是不兼容的。故事的寓意,对直接字符串访问要非常小心。
    • @LightnessRacesinOrbit 但在实践中,它会起作用。
    • @LightnessRacesinOrbit 没有故意保证连续性,以便允许按照rope 的方式实现。在实践中,没有人使用过它们,所以他们添加了连续性保证。而且std::string的g++实现一直是连续的;以上将与它一起使用。
    • @James: I don't believe that's true; JW 说strings are still COW in GCC 4.9,这不会破坏连续性保证吗?等等,是吗?嗯。是的,never mind I guess not.
    【解决方案3】:

    使用std::copy_n():

    std::copy_n(i, nSize, std::back_inserter(sMsg));
    

    【讨论】:

    • 如果您在读取 ​​n 字符之前遇到文件结尾,这将导致未定义的行为(而不是错误!)。
    • @JamesKanze 为什么会这样?
    • 因为标准是这样说的。为什么这么说,我不知道;我怀疑这只是作者不想具体说明任何内容的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 2020-01-14
    • 2011-12-07
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多