最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - How to copy from a std::string_view to a std::vector or std::string while avoiding allocation? - Stack Overflow

programmeradmin2浏览0评论

I am trying to copy a series of std::string_views into a std::vector<char> container, without causing additional memory allocation.

I thought that using std::copy would be the most straightforward approach.

auto buffer = std::vector<char>();
buffer.reserve(1024);

{
    const auto line = std::string_view("Content-Type: application/json\r\n");
    std::copy(line.begin(), line.end(), buffer.end());
}

{
    const auto line = std::string_view("Content-Length: 200\r\n");
    std::copy(line.begin(), line.end(), buffer.end());
}

In case it is not obvious, in each of the two above cases where std::copy is used, I am trying to copy the entire contents of line into buffer. The destination address should be the end of buffer.

However, this code is nonsensical.

It copies zero bytes of data. Having thought about it for a bit, I'm actually not sure exactly why this is the case. Initially I thought that it was because std::copy was checking the output iterator to ensure it remains in bound. However, I'm not sure how an iterator returned by buffer.end() would know whether or not it is in bounds or not. (Since this iterator does not have access to the other data members of buffer.) It was a silly thought...

To summarize:

  • I'm not sure why this doesn't work (why are zero bytes of data copied?)
  • This is probably not the right approach to the problem. What should I be doing instead?

By the way the intention behind using buffer.reserve was to avoid allocation.

Of course, one simple way to avoid an allocation would be to check the size of the source and remaining space in the destination first.

I am trying to copy a series of std::string_views into a std::vector<char> container, without causing additional memory allocation.

I thought that using std::copy would be the most straightforward approach.

auto buffer = std::vector<char>();
buffer.reserve(1024);

{
    const auto line = std::string_view("Content-Type: application/json\r\n");
    std::copy(line.begin(), line.end(), buffer.end());
}

{
    const auto line = std::string_view("Content-Length: 200\r\n");
    std::copy(line.begin(), line.end(), buffer.end());
}

In case it is not obvious, in each of the two above cases where std::copy is used, I am trying to copy the entire contents of line into buffer. The destination address should be the end of buffer.

However, this code is nonsensical.

It copies zero bytes of data. Having thought about it for a bit, I'm actually not sure exactly why this is the case. Initially I thought that it was because std::copy was checking the output iterator to ensure it remains in bound. However, I'm not sure how an iterator returned by buffer.end() would know whether or not it is in bounds or not. (Since this iterator does not have access to the other data members of buffer.) It was a silly thought...

To summarize:

  • I'm not sure why this doesn't work (why are zero bytes of data copied?)
  • This is probably not the right approach to the problem. What should I be doing instead?

By the way the intention behind using buffer.reserve was to avoid allocation.

Of course, one simple way to avoid an allocation would be to check the size of the source and remaining space in the destination first.

Share Improve this question edited Mar 14 at 11:49 user2138149 asked Mar 14 at 11:33 user2138149user2138149 17.7k30 gold badges149 silver badges296 bronze badges 3
  • 2 Overruing the buffer causes UB, so any behavior you observe is valid (including if the library checks out-of-bound access and copies 0 bytes). "The destination address should be the end of buffer" - why ? – wohlstad Commented Mar 14 at 11:36
  • 5 buffer.insert(buffer.end(), line.begin(), line.end()); – Raffallo Commented Mar 14 at 11:37
  • 2 And as a general rule, compile with -fsanitize=address or -fsanitize=undefined when in doubt. It'll save you from a lot of grief. – Passer By Commented Mar 14 at 11:42
Add a comment  | 

1 Answer 1

Reset to default 4

why are zero bytes of data copied?

Because you are dereferencing an iterator that is invalid to dereference. buffer.end() is approximately a char* that points one beyond the current last element. Writing past that, even only into the allocated chars (because you reserved some), doesn't change the size() reported by the buffer.

If you have C++23, then this is very simple:

buffer.append_range(line);

To use std::copy, you would need to pass an iterator that inserted into the container, rather than one that just pointed to an element.

std::copy(line.begin(), line.end(), std::back_inserter(buffer));
std::ranges::copy(line, std::back_inserter(buffer));
发布评论

评论列表(0)

  1. 暂无评论