直接从 std::istream 读取到 std::string

发布于 2024-08-13 01:55:52 字数 254 浏览 9 评论 0原文

无论如何,是否可以将已知数量的字节直接读取到 std::string 中,而不创建临时缓冲区来执行此操作?

例如目前我可以这样做

boost::uint16_t len;
is.read((char*)&len, 2);
char *tmpStr = new char[len];
is.read(tmpStr, len);
std::string str(tmpStr, len);
delete[] tmpStr;

Is there anyway to read a known number of bytes, directly into an std::string, without creating a temporary buffer to do so?

eg currently I can do it by

boost::uint16_t len;
is.read((char*)&len, 2);
char *tmpStr = new char[len];
is.read(tmpStr, len);
std::string str(tmpStr, len);
delete[] tmpStr;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

も让我眼熟你 2024-08-20 01:55:52

std::string 有一个可以使用的 resize 函数,或者一个可以执行相同操作的构造函数:

boost::uint16_t len;
is.read((char*)&len, 2);

std::string str(len, '\0');
is.read(&str[0], len);

这是未经测试的,我不知道字符串是否是强制的拥有连续的存储空间。

std::string has a resize function you could use, or a constructor that'll do the same:

boost::uint16_t len;
is.read((char*)&len, 2);

std::string str(len, '\0');
is.read(&str[0], len);

This is untested, and I don't know if strings are mandated to have contiguous storage.

℉絮湮 2024-08-20 01:55:52

您可以使用 copy_n 和 insert_iterator 的组合

void test_1816319()
{
    static char const* fname = "test_1816319.bin";
    std::ofstream ofs(fname, std::ios::binary);
    ofs.write("\x2\x0", 2);
    ofs.write("ab", 2);
    ofs.close();

    std::ifstream ifs(fname, std::ios::binary);
    std::string s;
    size_t n = 0;
    ifs.read((char*)&n, 2);
    std::istream_iterator<char> isi(ifs), isiend;
    std::copy_n(isi, n, std::insert_iterator<std::string>(s, s.begin()));
    ifs.close();
    _unlink(fname);

    std::cout << s << std::endl;
}

,没有复制,没有黑客,没有溢出的可能性,没有未定义的行为。

You could use a combination of copy_n and an insert_iterator

void test_1816319()
{
    static char const* fname = "test_1816319.bin";
    std::ofstream ofs(fname, std::ios::binary);
    ofs.write("\x2\x0", 2);
    ofs.write("ab", 2);
    ofs.close();

    std::ifstream ifs(fname, std::ios::binary);
    std::string s;
    size_t n = 0;
    ifs.read((char*)&n, 2);
    std::istream_iterator<char> isi(ifs), isiend;
    std::copy_n(isi, n, std::insert_iterator<std::string>(s, s.begin()));
    ifs.close();
    _unlink(fname);

    std::cout << s << std::endl;
}

no copying, no hacks, no possibility of overrun, no undefined behaviour.

罪歌 2024-08-20 01:55:52

我会使用向量作为缓冲区。

boost::uint16_t len;
is.read((char*)&len, 2); // Note if this file was saved from a different architecture 
                         // then endianness of these two bytes may be reversed.

std::vector buffer(len);  // uninitialized.
is.read(&buffer[0], len);

std::string  str(buffer.begin(),buffer.end());

尽管您可能会使用字符串作为缓冲区(如 GMan 所描述的)。标准不保证字符串成员位于连续位置(因此请检查当前的实现并添加一个大注释,表明在移植到另一个编译器/平台时需要检查)。

I would use a vector as the buffer.

boost::uint16_t len;
is.read((char*)&len, 2); // Note if this file was saved from a different architecture 
                         // then endianness of these two bytes may be reversed.

std::vector buffer(len);  // uninitialized.
is.read(&buffer[0], len);

std::string  str(buffer.begin(),buffer.end());

Though you will probably get away with using a string as the buffer (as described by GMan). It is not guaranteed by the standard that a strings members are in consecutive locations (so check your current implementation and put a big comment that it needs checking when porting to another compiler/platform).

清浅ˋ旧时光 2024-08-20 01:55:52

你可以使用像 getline 这样的东西:

#include <iostream>
#include <string>
using namespace std;

int main () {
  string str;
  getline (cin,str,' ');
}

You could use something like getline:

#include <iostream>
#include <string>
using namespace std;

int main () {
  string str;
  getline (cin,str,' ');
}
怀中猫帐中妖 2024-08-20 01:55:52

您只是优化代码长度还是想在这里保存一份副本?临时缓冲区出了什么问题?

我认为你实际上是在规避字符串的保护,试图直接这样写。如果您担心复制到 std::string 的性能,因为您已经确定它在某种程度上影响应用程序的性能,那么我会直接使用 char*。

编辑:做更多的事情......
从 char* 初始化 std::string 而不复制

在第二个答案中,它是非常明确地指出,您无法实现您想要实现的目标(即填充 std::string 而不对 char* 进行迭代来复制。)

看看您的加载例程(也许将其发布在这里?)并最小化分配:new 和delete 当然不是免费的,所以如果您不必不断地重新创建缓冲区,您至少可以节省一些时间。我总是发现通过将缓冲区 memset 为 0 或 null 终止每次迭代的数组的第一个索引来擦除它很有帮助,但是一旦您对算法充满信心,您可以为了性能而快速消除该代码。

Are you just optimizing code length or trying to save yourself a copy here? What's wrong with the temporary buffer?

I'd argue that you're actually circumventing the protections of the string trying to write directly do it like that. If you're worried about performance of the copy to a std::string because you've identified that it's in some way affecting the performance of your application, I'd work directly with the char*.

EDIT: Doing more looking...
initializing std::string from char* without copy

In the second answer, it's stated pretty flatly that you can't achieve what you're looking to achieve (ie. populate a std::string without an iteration over the char* to copy.)

Take a look at your load routine (post it here perhaps?) and minimize allocations: new and delete certainly aren't free so you can at least save some time if you don't have to re-create the buffer constantly. I always find it helpful erase it by memset'ing the buffer to 0 or null terminating the first index of the array each iteration but you may quickly eliminate that code in the interests of performance once you're confident in your algorithm.

死开点丶别碍眼 2024-08-20 01:55:52

一个简单的方法是:

std::istream& data
const size_t dataSize(static_cast<size_t>(data.rdbuf()->in_avail()));
std::string content;
content.reserve( dataSize);
data.read(&content[0], dataSize);

An easy way would be:

std::istream& data
const size_t dataSize(static_cast<size_t>(data.rdbuf()->in_avail()));
std::string content;
content.reserve( dataSize);
data.read(&content[0], dataSize);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文