Are there downsides to using std::string as a buffer?Meaning of acronym SSO in the context of std::stringBenefits of vector<char> over string?Understanding GCC 5's _GLIBCXX_USE_CXX11_ABI or the new ABIHow to create a std::string directly from a char* array without copying?Can you avoid using temporary buffers when using std::string to interact with C style APIs?Specific behaviour of std::string on visual studio?Google protocol buffers and use of std::string for arbitrary binary dataCan I safely use std::string for binary data in C++11?Using a shared_ptr<string> into an unordered_set<string>Sockets: getting UDP data into a word-aligned buffer using recvfrom without memcpy?Why std::string hasn't const char* cast operator in C++11?std::string how to do a constructor like std::string(char* allocated_outside)Giving char* to std::string for management (to eventually free memory)

Why did the people of Zion never find evidence of the previous cycles?

How can I determine if two vertices on a polygon are consecutive?

Continents with simplex noise

windows 10 computer waking up from sleep

Starting a fire in a cold planet that was full of flammable gas

What's the earliest a champion can have a focus pool of 3?

70 million rials in usurious money

What happens to a Bladesinger reincarnated as a Human?

How is warfare affected when armor has (temporally) outpaced guns? How can guns compete?

Meaning of "in arms"

Why buy a first class ticket on Southern trains?

What happens on pressing Ctrl-T in a terminal when a program is running?

Reviewer wants me to do massive amount of work, the result would be a different article. Should I tell that to the editor?

What game(s) does Michael play in Mind Field S2E4?

Will there be a vote in the Commons to decide the fate of Johnson's deal?

Asking my PhD advisor for a postdoc position. Is it bad to appear desperate?

Is it bizarre that a professor asks every student for a 3 inch by 5 inch photograph?

How does the Gameboy Link Cable work?

I'm being drafted to the military but I have the option to refuse (legally), would it be immoral for me to serve?

What's the physical meaning of the standard base vectors?

Command which removes data left side of ";" (semicolon) on each row

Why past tense of vomit generally spelled 'vomited' rather than 'vomitted'?

Leaving passport in the hotel room

Travel with Expired Greek Passport from UK to Greece and Return



Are there downsides to using std::string as a buffer?


Meaning of acronym SSO in the context of std::stringBenefits of vector<char> over string?Understanding GCC 5's _GLIBCXX_USE_CXX11_ABI or the new ABIHow to create a std::string directly from a char* array without copying?Can you avoid using temporary buffers when using std::string to interact with C style APIs?Specific behaviour of std::string on visual studio?Google protocol buffers and use of std::string for arbitrary binary dataCan I safely use std::string for binary data in C++11?Using a shared_ptr<string> into an unordered_set<string>Sockets: getting UDP data into a word-aligned buffer using recvfrom without memcpy?Why std::string hasn't const char* cast operator in C++11?std::string how to do a constructor like std::string(char* allocated_outside)Giving char* to std::string for management (to eventually free memory)






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;









68

















I have recently seen a colleague of mine using std::string as a buffer:



std::string receive_data(const Receiver& receiver) 
std::string buff;
int size = receiver.size();
if (size > 0)
buff.resize(size);
const char* dst_ptr = buff.data();
const char* src_ptr = receiver.data();
memcpy((char*) dst_ptr, src_ptr, size);

return buff;



I guess this guy wants to take advantage of auto destruction of the returned string so he needs not worry about freeing of the allocated buffer.



This looks a bit strange to me since according to cplusplus.com the data() method returns a const char* pointing to a buffer internally managed by the string:



const char* data() const noexcept;


Memcpy-ing to a const char pointer? AFAIK this does no harm as long as we know what we do, but have I missed something? Is this dangerous?










share|improve this question























  • 28





    With C++17 data() has an overload returning a pointer to non-const qualified char.

    – VTT
    Jun 3 at 7:35






  • 38





    ...which is mentioned by cppreference. cplusplus.com is not the best source.

    – HolyBlackCat
    Jun 3 at 7:36






  • 11





    I think that the operation of casting from const char* to char* by itself implies some sort of hazard in your program. If dst_ptr points to a read-only memory block, then you should not attempt to write into that block using this pointer.

    – goodvibration
    Jun 3 at 7:37







  • 6





    Whenever you see code using C-style casts (like e.g. (char*) dst_ptr) you should take that as a red flag.

    – Some programmer dude
    Jun 3 at 7:38






  • 9





    I think this question is mostly opinion-based. IMO using std::string as a buffer is fine if you know you're receiving text data. If you're receiving binary data std::vector<char> is probably a better choice.

    – Miles Budnek
    Jun 3 at 7:42

















68

















I have recently seen a colleague of mine using std::string as a buffer:



std::string receive_data(const Receiver& receiver) 
std::string buff;
int size = receiver.size();
if (size > 0)
buff.resize(size);
const char* dst_ptr = buff.data();
const char* src_ptr = receiver.data();
memcpy((char*) dst_ptr, src_ptr, size);

return buff;



I guess this guy wants to take advantage of auto destruction of the returned string so he needs not worry about freeing of the allocated buffer.



This looks a bit strange to me since according to cplusplus.com the data() method returns a const char* pointing to a buffer internally managed by the string:



const char* data() const noexcept;


Memcpy-ing to a const char pointer? AFAIK this does no harm as long as we know what we do, but have I missed something? Is this dangerous?










share|improve this question























  • 28





    With C++17 data() has an overload returning a pointer to non-const qualified char.

    – VTT
    Jun 3 at 7:35






  • 38





    ...which is mentioned by cppreference. cplusplus.com is not the best source.

    – HolyBlackCat
    Jun 3 at 7:36






  • 11





    I think that the operation of casting from const char* to char* by itself implies some sort of hazard in your program. If dst_ptr points to a read-only memory block, then you should not attempt to write into that block using this pointer.

    – goodvibration
    Jun 3 at 7:37







  • 6





    Whenever you see code using C-style casts (like e.g. (char*) dst_ptr) you should take that as a red flag.

    – Some programmer dude
    Jun 3 at 7:38






  • 9





    I think this question is mostly opinion-based. IMO using std::string as a buffer is fine if you know you're receiving text data. If you're receiving binary data std::vector<char> is probably a better choice.

    – Miles Budnek
    Jun 3 at 7:42













68












68








68


8






I have recently seen a colleague of mine using std::string as a buffer:



std::string receive_data(const Receiver& receiver) 
std::string buff;
int size = receiver.size();
if (size > 0)
buff.resize(size);
const char* dst_ptr = buff.data();
const char* src_ptr = receiver.data();
memcpy((char*) dst_ptr, src_ptr, size);

return buff;



I guess this guy wants to take advantage of auto destruction of the returned string so he needs not worry about freeing of the allocated buffer.



This looks a bit strange to me since according to cplusplus.com the data() method returns a const char* pointing to a buffer internally managed by the string:



const char* data() const noexcept;


Memcpy-ing to a const char pointer? AFAIK this does no harm as long as we know what we do, but have I missed something? Is this dangerous?










share|improve this question

















I have recently seen a colleague of mine using std::string as a buffer:



std::string receive_data(const Receiver& receiver) 
std::string buff;
int size = receiver.size();
if (size > 0)
buff.resize(size);
const char* dst_ptr = buff.data();
const char* src_ptr = receiver.data();
memcpy((char*) dst_ptr, src_ptr, size);

return buff;



I guess this guy wants to take advantage of auto destruction of the returned string so he needs not worry about freeing of the allocated buffer.



This looks a bit strange to me since according to cplusplus.com the data() method returns a const char* pointing to a buffer internally managed by the string:



const char* data() const noexcept;


Memcpy-ing to a const char pointer? AFAIK this does no harm as long as we know what we do, but have I missed something? Is this dangerous?







c++ c++11 stdstring






share|improve this question
















share|improve this question













share|improve this question




share|improve this question








edited Jun 3 at 18:02









TylerH

16.7k10 gold badges57 silver badges72 bronze badges




16.7k10 gold badges57 silver badges72 bronze badges










asked Jun 3 at 7:33









duong_dajgjaduong_dajgja

2,1861 gold badge19 silver badges41 bronze badges




2,1861 gold badge19 silver badges41 bronze badges










  • 28





    With C++17 data() has an overload returning a pointer to non-const qualified char.

    – VTT
    Jun 3 at 7:35






  • 38





    ...which is mentioned by cppreference. cplusplus.com is not the best source.

    – HolyBlackCat
    Jun 3 at 7:36






  • 11





    I think that the operation of casting from const char* to char* by itself implies some sort of hazard in your program. If dst_ptr points to a read-only memory block, then you should not attempt to write into that block using this pointer.

    – goodvibration
    Jun 3 at 7:37







  • 6





    Whenever you see code using C-style casts (like e.g. (char*) dst_ptr) you should take that as a red flag.

    – Some programmer dude
    Jun 3 at 7:38






  • 9





    I think this question is mostly opinion-based. IMO using std::string as a buffer is fine if you know you're receiving text data. If you're receiving binary data std::vector<char> is probably a better choice.

    – Miles Budnek
    Jun 3 at 7:42












  • 28





    With C++17 data() has an overload returning a pointer to non-const qualified char.

    – VTT
    Jun 3 at 7:35






  • 38





    ...which is mentioned by cppreference. cplusplus.com is not the best source.

    – HolyBlackCat
    Jun 3 at 7:36






  • 11





    I think that the operation of casting from const char* to char* by itself implies some sort of hazard in your program. If dst_ptr points to a read-only memory block, then you should not attempt to write into that block using this pointer.

    – goodvibration
    Jun 3 at 7:37







  • 6





    Whenever you see code using C-style casts (like e.g. (char*) dst_ptr) you should take that as a red flag.

    – Some programmer dude
    Jun 3 at 7:38






  • 9





    I think this question is mostly opinion-based. IMO using std::string as a buffer is fine if you know you're receiving text data. If you're receiving binary data std::vector<char> is probably a better choice.

    – Miles Budnek
    Jun 3 at 7:42







28




28





With C++17 data() has an overload returning a pointer to non-const qualified char.

– VTT
Jun 3 at 7:35





With C++17 data() has an overload returning a pointer to non-const qualified char.

– VTT
Jun 3 at 7:35




38




38





...which is mentioned by cppreference. cplusplus.com is not the best source.

– HolyBlackCat
Jun 3 at 7:36





...which is mentioned by cppreference. cplusplus.com is not the best source.

– HolyBlackCat
Jun 3 at 7:36




11




11





I think that the operation of casting from const char* to char* by itself implies some sort of hazard in your program. If dst_ptr points to a read-only memory block, then you should not attempt to write into that block using this pointer.

– goodvibration
Jun 3 at 7:37






I think that the operation of casting from const char* to char* by itself implies some sort of hazard in your program. If dst_ptr points to a read-only memory block, then you should not attempt to write into that block using this pointer.

– goodvibration
Jun 3 at 7:37





6




6





Whenever you see code using C-style casts (like e.g. (char*) dst_ptr) you should take that as a red flag.

– Some programmer dude
Jun 3 at 7:38





Whenever you see code using C-style casts (like e.g. (char*) dst_ptr) you should take that as a red flag.

– Some programmer dude
Jun 3 at 7:38




9




9





I think this question is mostly opinion-based. IMO using std::string as a buffer is fine if you know you're receiving text data. If you're receiving binary data std::vector<char> is probably a better choice.

– Miles Budnek
Jun 3 at 7:42





I think this question is mostly opinion-based. IMO using std::string as a buffer is fine if you know you're receiving text data. If you're receiving binary data std::vector<char> is probably a better choice.

– Miles Budnek
Jun 3 at 7:42












7 Answers
7






active

oldest

votes


















70


















Don't use std::string as a buffer.



It is bad practice to use std::string as a buffer, for several reasons (listed in no particular order):




  • std::string was not intended for use as a buffer; you would need to double-check the description of the class to make sure there are no "gotchas" which would prevent certain usage patterns (or make them trigger undefined behavior).

  • As a concrete example: Before C++17, you can't even write through the pointer you get with data() - it's const Tchar *; so your code would cause undefined behavior. (But &(str[0]), &(str.front()), or &(*(str.begin())) would work.)

  • Using std::strings for buffers is confusing to readers of the implementation, who assume you would be using std::string for, well, strings. In other words, doing so breaks the Principle of Least Astonishment.

  • Worse yet, it's confusing for whoever might use this function - they too may think what you're returning is a string, i.e. valid human-readable text.


  • std::unique_ptr would be fine for your case, or even std::vector. In C++17, you can use std::byte for the element type, too. A more sophisticated option is a class with an SSO-like feature, e.g. Boost's small_vector (thank you, @gast128, for mentioning it).

  • (Minor point:) libstdc++ had to change its ABI for std::string to conform to the C++11 standard, which in some cases (which by now are rather unlikely), you might run into some linkage or runtime issues that you wouldn't with a different type for your buffer.

Also, your code may make two instead of one heap allocations (implementation dependent): Once upon string construction and another when resize()ing. But that in itself is not really a reason to avoid std::string, since you can avoid the double allocation using the construction in @Jarod42's answer.






share|improve this answer























  • 3





    Can you explain what you mean in the first bullet point? What "gotchas" ?

    – M.M
    Jun 3 at 8:08






  • 2





    And with std::string_view, you can define readable portions of the buffer.

    – Zereges
    Jun 3 at 8:09






  • 16





    @M.M For example the terminating character which std::string guarantees to be present. Would you know off-hand whether it is included in the valid range of data()? Overwriting it is UB! It needs a few extra mental cycles (and possibly reference lookups) to verify this function does not have UB from that.

    – Max Langhof
    Jun 3 at 8:13







  • 3





    @M.M: The point is - you don't intuitively know! I wasn't even aware of what MaxLanghof wrote in his comment.

    – einpoklum
    Jun 3 at 9:56






  • 5





    +1 for std::byte, unbelievable I haven't heard of it before! It's crazy how often one looks into some C++ reference every day and still new things keep popping up...

    – andreee
    Jun 3 at 20:08


















64


















You can completely avoid a manual memcpy by calling the appropriate constructor:



std::string receive_data(const Receiver& receiver) 
return receiver.data(), receiver.size();



That even handles in a string.



BTW, unless content is actually text, I would prefer std::vector<std::byte> (or equivalent).






share|improve this answer























  • 4





    As original buffer data should not be not const, you should not have UB.

    – Jarod42
    Jun 3 at 7:56






  • 14





    And by then a good programmer goes: "Why the hell do I need a separate one-liner conversion function? Not only that, but this function named 'receive' doesn't actually perform any 'receiving'. Delete!"

    – screwnut
    Jun 3 at 8:32







  • 6





    @screwnut: To be fair, it is theoretically possible that receiver.data() waits on the reception to happen, or does something else beyond returning a member pointer.

    – einpoklum
    Jun 3 at 22:53






  • 9





    @screwnut: Then I'm a bad programmer; I'll keep the conversion in a separate function, even if it's a one liner, because I appreciate abstraction and do not like to repeat myself. If I later need to add some checks, some logging, etc... the function is right here and I don't have to hunt around the codebase for all instances of conversion.

    – Matthieu M.
    Jun 4 at 6:58






  • 5





    @screwnut: Prefer non-member non-friend functions.

    – Matthieu M.
    Jun 4 at 10:57


















9



















Memcpy-ing to a const char pointer? AFAIK this does no harm as long as we know what we do, but is this good behavior and why?




The current code may have undefined behavior, depending on the C++ version. To avoid undefined behavior in C++14 and below take the address of the first element. It yields a non-const pointer:



buff.resize(size);
memcpy(&buff[0], &receiver[0], size);




I have recently seen a colleague of mine using std::string as a buffer...




That was somewhat common in older code, especially circa C++03. There are several benefits and downsides to using a string like that. Depending on what you are doing with the code, std::vector can be a bit anemic, and you sometimes used a string instead and accepted the extra overhead of char_traits.



For example, std::string is usually a faster container than std::vector on append, and you can't return std::vector from a function. (Or you could not do so in practice in C++98 because C++98 required the vector to be constructed in the function and copied out). Additionally, std::string allowed you to search with a richer assortment of member functions, like find_first_of and find_first_not_of. That was convenient when searching though arrays of bytes.



I think what you really want/need is SGI's Rope class, but it never made it into the STL. It looks like GCC's libstdc++ may provide it.




There a lengthy discussion about this being legal in C++14 and below:



const char* dst_ptr = buff.data();
const char* src_ptr = receiver.data();
memcpy((char*) dst_ptr, src_ptr, size);


I know for certain it is not safe in GCC. I once did something like this in some self tests and it resulted in a segfault:



std::string buff("A");
...

char* ptr = (char*)buff.data();
size_t len = buff.size();

ptr[0] ^= 1; // tamper with byte
bool tampered = HMAC(key, ptr, len, mac);


GCC put the single byte 'A' in register AL. The high 3-bytes were garbage, so the 32-bit register was 0xXXXXXX41. When I dereferenced at ptr[0], GCC dereferenced a garbage address 0xXXXXXX41.



The two take-aways for me were, don't write half-ass self tests, and don't try to make data() a non-const pointer.






share|improve this answer























  • 7





    Prefer std::copy for type-safety. It won't be slower.

    – Lightness Races in Orbit
    Jun 3 at 17:07






  • 3





    Seems like the only answer directly answering the question.

    – Keith
    Jun 4 at 0:59






  • 2





    "you can't return std::vector from a function. (Or you could not do so back in C++98 or C++03)" is wrong.

    – Ben Voigt
    Jun 4 at 2:38






  • 3





    And it has never been a legal optimization for a compiler to confuse an address with stored content. buff.data() cannot be a register containing 'A', it must be an address.

    – Ben Voigt
    Jun 4 at 2:40







  • 2





    @jww: Indeed, although you could avoid that copy with NRVO and a swap() call. But the copy would also be required of std::string. Small string optimization could make it a little better. I think some implementations tried to solve this using copy-on-write (for string, never allowed for vector) but even in C++98 and C++03 there were some specifications on std::string that couldn't be reasonable met by COW. Of course rvalue references and moves solved it neatly.

    – Ben Voigt
    Jun 4 at 3:01



















7


















From C++17, data can return a non const char *.



Draft n4659 declares at [string.accessors]:




const charT* c_str() const noexcept;
const charT* data() const noexcept;
....
charT* data() noexcept;






share|improve this answer





















  • 8





    @SergeBallesta - Removing a const qualifier is not UB. Modifying a const object is UB. The object in question is not const.

    – StoryTeller
    Jun 3 at 7:59






  • 6





    @SergeBallesta - Seriously? And how do you reconcile that with &str[0] being a non-const pointer to the very same buffer? The object is guaranteed not to be const. The core rules of the language still apply, even to pointers returned from library types, ergo, no UB.

    – StoryTeller
    Jun 3 at 8:05







  • 4





    @Jarod42: I agree that I am nitpicking here, but the library could expect the buffer not be be changed, and later reuse a cached version. Coming for old K&R C I am now frightened by optimizing compilers and very cautious for constness and strict aliasing.

    – Serge Ballesta
    Jun 3 at 8:07







  • 8





    @StoryTeller Serge is correct that "Modifying the character array accessed through the const overload of data has undefined behavior." according to cppreference and the standard.

    – Max Langhof
    Jun 3 at 8:16







  • 4





    (For completeness, here is the C++11 wording: timsong-cpp.github.io/cppwp/n3337/string.ops#string.accessors-3)

    – Max Langhof
    Jun 3 at 8:22


















7


















The code is unnecessary, considering that



std::string receive_data(const Receiver& receiver) 
std::string buff;
int size = receiver.size();
if (size > 0)
buff.assign(receiver.data(), size);

return buff;



will do exactly the same.






share|improve this answer





















  • 2





    You can cut even more code; the if is also unnecessary. assign will be a no-op then. But continue to unnecessary remove code, and you end up with Jarod42's answer. None of these lines are necessary, as std::string already has an appropriate constructor.

    – MSalters
    Jun 4 at 11:32











  • @MSalters I prefer not to assume things that are not given. What if receiver.size() can return negative values?

    – Kit.
    Jun 5 at 14:02











  • That would be rather unexpected, given that sizes are typically a size_t and therefore unsigned. That does show a possible problem with your code: it might suffer from signed integer overflow, which is undefined behavior. And that's on a code path which handles input, so this may constitute an externally exploitable vulnerability.

    – MSalters
    Jun 6 at 8:53











  • @MSalters True, Jarod42's changes could introduce an externally exploitable vulnerability. They could also introduce crashes if receiver.data() is UB when receiver.size() is zero.

    – Kit.
    Jun 7 at 7:41


















5


















The big optimization opportunity I would investigate here is: Receiver appears to be some kind of container that supports .data() and .size(). If you can consume it, and pass it in as a rvalue reference Receiver&&, you might be able to use move semantics without making any copies at all! If it’s got an iterator interface, you could use those for range-based constructors or std::move() from <algorithm>.



In C++17 (as Serge Ballesta and others have mentioned), std::string::data() returns a pointer to non-const data. A std::string has been guaranteed to store all its data contiguously for years.



The code as written smells a bit, although it’s not really the programmer’s fault: those hacks were necessary at the time. Today, you should at least change the type of dst_ptr from const char* to char* and remove the cast in the first argument to memcpy(). You could also reserve() a number of bytes for the buffer and then use a STL function to move the data.



As others have mentioned, a std::vector or std::unique_ptr would be a more natural data structure to use here.






share|improve this answer



































    4


















    One downside is performance.
    The .resize method will default-initialize all the new byte locations to 0.
    That initialization is unnecessary if you're then going to overwrite the 0s with other data.






    share|improve this answer



























      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );














      draft saved

      draft discarded
















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56422913%2fare-there-downsides-to-using-stdstring-as-a-buffer%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown


























      7 Answers
      7






      active

      oldest

      votes








      7 Answers
      7






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      70


















      Don't use std::string as a buffer.



      It is bad practice to use std::string as a buffer, for several reasons (listed in no particular order):




      • std::string was not intended for use as a buffer; you would need to double-check the description of the class to make sure there are no "gotchas" which would prevent certain usage patterns (or make them trigger undefined behavior).

      • As a concrete example: Before C++17, you can't even write through the pointer you get with data() - it's const Tchar *; so your code would cause undefined behavior. (But &(str[0]), &(str.front()), or &(*(str.begin())) would work.)

      • Using std::strings for buffers is confusing to readers of the implementation, who assume you would be using std::string for, well, strings. In other words, doing so breaks the Principle of Least Astonishment.

      • Worse yet, it's confusing for whoever might use this function - they too may think what you're returning is a string, i.e. valid human-readable text.


      • std::unique_ptr would be fine for your case, or even std::vector. In C++17, you can use std::byte for the element type, too. A more sophisticated option is a class with an SSO-like feature, e.g. Boost's small_vector (thank you, @gast128, for mentioning it).

      • (Minor point:) libstdc++ had to change its ABI for std::string to conform to the C++11 standard, which in some cases (which by now are rather unlikely), you might run into some linkage or runtime issues that you wouldn't with a different type for your buffer.

      Also, your code may make two instead of one heap allocations (implementation dependent): Once upon string construction and another when resize()ing. But that in itself is not really a reason to avoid std::string, since you can avoid the double allocation using the construction in @Jarod42's answer.






      share|improve this answer























      • 3





        Can you explain what you mean in the first bullet point? What "gotchas" ?

        – M.M
        Jun 3 at 8:08






      • 2





        And with std::string_view, you can define readable portions of the buffer.

        – Zereges
        Jun 3 at 8:09






      • 16





        @M.M For example the terminating character which std::string guarantees to be present. Would you know off-hand whether it is included in the valid range of data()? Overwriting it is UB! It needs a few extra mental cycles (and possibly reference lookups) to verify this function does not have UB from that.

        – Max Langhof
        Jun 3 at 8:13







      • 3





        @M.M: The point is - you don't intuitively know! I wasn't even aware of what MaxLanghof wrote in his comment.

        – einpoklum
        Jun 3 at 9:56






      • 5





        +1 for std::byte, unbelievable I haven't heard of it before! It's crazy how often one looks into some C++ reference every day and still new things keep popping up...

        – andreee
        Jun 3 at 20:08















      70


















      Don't use std::string as a buffer.



      It is bad practice to use std::string as a buffer, for several reasons (listed in no particular order):




      • std::string was not intended for use as a buffer; you would need to double-check the description of the class to make sure there are no "gotchas" which would prevent certain usage patterns (or make them trigger undefined behavior).

      • As a concrete example: Before C++17, you can't even write through the pointer you get with data() - it's const Tchar *; so your code would cause undefined behavior. (But &(str[0]), &(str.front()), or &(*(str.begin())) would work.)

      • Using std::strings for buffers is confusing to readers of the implementation, who assume you would be using std::string for, well, strings. In other words, doing so breaks the Principle of Least Astonishment.

      • Worse yet, it's confusing for whoever might use this function - they too may think what you're returning is a string, i.e. valid human-readable text.


      • std::unique_ptr would be fine for your case, or even std::vector. In C++17, you can use std::byte for the element type, too. A more sophisticated option is a class with an SSO-like feature, e.g. Boost's small_vector (thank you, @gast128, for mentioning it).

      • (Minor point:) libstdc++ had to change its ABI for std::string to conform to the C++11 standard, which in some cases (which by now are rather unlikely), you might run into some linkage or runtime issues that you wouldn't with a different type for your buffer.

      Also, your code may make two instead of one heap allocations (implementation dependent): Once upon string construction and another when resize()ing. But that in itself is not really a reason to avoid std::string, since you can avoid the double allocation using the construction in @Jarod42's answer.






      share|improve this answer























      • 3





        Can you explain what you mean in the first bullet point? What "gotchas" ?

        – M.M
        Jun 3 at 8:08






      • 2





        And with std::string_view, you can define readable portions of the buffer.

        – Zereges
        Jun 3 at 8:09






      • 16





        @M.M For example the terminating character which std::string guarantees to be present. Would you know off-hand whether it is included in the valid range of data()? Overwriting it is UB! It needs a few extra mental cycles (and possibly reference lookups) to verify this function does not have UB from that.

        – Max Langhof
        Jun 3 at 8:13







      • 3





        @M.M: The point is - you don't intuitively know! I wasn't even aware of what MaxLanghof wrote in his comment.

        – einpoklum
        Jun 3 at 9:56






      • 5





        +1 for std::byte, unbelievable I haven't heard of it before! It's crazy how often one looks into some C++ reference every day and still new things keep popping up...

        – andreee
        Jun 3 at 20:08













      70














      70










      70









      Don't use std::string as a buffer.



      It is bad practice to use std::string as a buffer, for several reasons (listed in no particular order):




      • std::string was not intended for use as a buffer; you would need to double-check the description of the class to make sure there are no "gotchas" which would prevent certain usage patterns (or make them trigger undefined behavior).

      • As a concrete example: Before C++17, you can't even write through the pointer you get with data() - it's const Tchar *; so your code would cause undefined behavior. (But &(str[0]), &(str.front()), or &(*(str.begin())) would work.)

      • Using std::strings for buffers is confusing to readers of the implementation, who assume you would be using std::string for, well, strings. In other words, doing so breaks the Principle of Least Astonishment.

      • Worse yet, it's confusing for whoever might use this function - they too may think what you're returning is a string, i.e. valid human-readable text.


      • std::unique_ptr would be fine for your case, or even std::vector. In C++17, you can use std::byte for the element type, too. A more sophisticated option is a class with an SSO-like feature, e.g. Boost's small_vector (thank you, @gast128, for mentioning it).

      • (Minor point:) libstdc++ had to change its ABI for std::string to conform to the C++11 standard, which in some cases (which by now are rather unlikely), you might run into some linkage or runtime issues that you wouldn't with a different type for your buffer.

      Also, your code may make two instead of one heap allocations (implementation dependent): Once upon string construction and another when resize()ing. But that in itself is not really a reason to avoid std::string, since you can avoid the double allocation using the construction in @Jarod42's answer.






      share|improve this answer
















      Don't use std::string as a buffer.



      It is bad practice to use std::string as a buffer, for several reasons (listed in no particular order):




      • std::string was not intended for use as a buffer; you would need to double-check the description of the class to make sure there are no "gotchas" which would prevent certain usage patterns (or make them trigger undefined behavior).

      • As a concrete example: Before C++17, you can't even write through the pointer you get with data() - it's const Tchar *; so your code would cause undefined behavior. (But &(str[0]), &(str.front()), or &(*(str.begin())) would work.)

      • Using std::strings for buffers is confusing to readers of the implementation, who assume you would be using std::string for, well, strings. In other words, doing so breaks the Principle of Least Astonishment.

      • Worse yet, it's confusing for whoever might use this function - they too may think what you're returning is a string, i.e. valid human-readable text.


      • std::unique_ptr would be fine for your case, or even std::vector. In C++17, you can use std::byte for the element type, too. A more sophisticated option is a class with an SSO-like feature, e.g. Boost's small_vector (thank you, @gast128, for mentioning it).

      • (Minor point:) libstdc++ had to change its ABI for std::string to conform to the C++11 standard, which in some cases (which by now are rather unlikely), you might run into some linkage or runtime issues that you wouldn't with a different type for your buffer.

      Also, your code may make two instead of one heap allocations (implementation dependent): Once upon string construction and another when resize()ing. But that in itself is not really a reason to avoid std::string, since you can avoid the double allocation using the construction in @Jarod42's answer.







      share|improve this answer















      share|improve this answer




      share|improve this answer








      edited Jul 4 at 19:32

























      answered Jun 3 at 7:56









      einpoklumeinpoklum

      45k30 gold badges160 silver badges314 bronze badges




      45k30 gold badges160 silver badges314 bronze badges










      • 3





        Can you explain what you mean in the first bullet point? What "gotchas" ?

        – M.M
        Jun 3 at 8:08






      • 2





        And with std::string_view, you can define readable portions of the buffer.

        – Zereges
        Jun 3 at 8:09






      • 16





        @M.M For example the terminating character which std::string guarantees to be present. Would you know off-hand whether it is included in the valid range of data()? Overwriting it is UB! It needs a few extra mental cycles (and possibly reference lookups) to verify this function does not have UB from that.

        – Max Langhof
        Jun 3 at 8:13







      • 3





        @M.M: The point is - you don't intuitively know! I wasn't even aware of what MaxLanghof wrote in his comment.

        – einpoklum
        Jun 3 at 9:56






      • 5





        +1 for std::byte, unbelievable I haven't heard of it before! It's crazy how often one looks into some C++ reference every day and still new things keep popping up...

        – andreee
        Jun 3 at 20:08












      • 3





        Can you explain what you mean in the first bullet point? What "gotchas" ?

        – M.M
        Jun 3 at 8:08






      • 2





        And with std::string_view, you can define readable portions of the buffer.

        – Zereges
        Jun 3 at 8:09






      • 16





        @M.M For example the terminating character which std::string guarantees to be present. Would you know off-hand whether it is included in the valid range of data()? Overwriting it is UB! It needs a few extra mental cycles (and possibly reference lookups) to verify this function does not have UB from that.

        – Max Langhof
        Jun 3 at 8:13







      • 3





        @M.M: The point is - you don't intuitively know! I wasn't even aware of what MaxLanghof wrote in his comment.

        – einpoklum
        Jun 3 at 9:56






      • 5





        +1 for std::byte, unbelievable I haven't heard of it before! It's crazy how often one looks into some C++ reference every day and still new things keep popping up...

        – andreee
        Jun 3 at 20:08







      3




      3





      Can you explain what you mean in the first bullet point? What "gotchas" ?

      – M.M
      Jun 3 at 8:08





      Can you explain what you mean in the first bullet point? What "gotchas" ?

      – M.M
      Jun 3 at 8:08




      2




      2





      And with std::string_view, you can define readable portions of the buffer.

      – Zereges
      Jun 3 at 8:09





      And with std::string_view, you can define readable portions of the buffer.

      – Zereges
      Jun 3 at 8:09




      16




      16





      @M.M For example the terminating character which std::string guarantees to be present. Would you know off-hand whether it is included in the valid range of data()? Overwriting it is UB! It needs a few extra mental cycles (and possibly reference lookups) to verify this function does not have UB from that.

      – Max Langhof
      Jun 3 at 8:13






      @M.M For example the terminating character which std::string guarantees to be present. Would you know off-hand whether it is included in the valid range of data()? Overwriting it is UB! It needs a few extra mental cycles (and possibly reference lookups) to verify this function does not have UB from that.

      – Max Langhof
      Jun 3 at 8:13





      3




      3





      @M.M: The point is - you don't intuitively know! I wasn't even aware of what MaxLanghof wrote in his comment.

      – einpoklum
      Jun 3 at 9:56





      @M.M: The point is - you don't intuitively know! I wasn't even aware of what MaxLanghof wrote in his comment.

      – einpoklum
      Jun 3 at 9:56




      5




      5





      +1 for std::byte, unbelievable I haven't heard of it before! It's crazy how often one looks into some C++ reference every day and still new things keep popping up...

      – andreee
      Jun 3 at 20:08





      +1 for std::byte, unbelievable I haven't heard of it before! It's crazy how often one looks into some C++ reference every day and still new things keep popping up...

      – andreee
      Jun 3 at 20:08













      64


















      You can completely avoid a manual memcpy by calling the appropriate constructor:



      std::string receive_data(const Receiver& receiver) 
      return receiver.data(), receiver.size();



      That even handles in a string.



      BTW, unless content is actually text, I would prefer std::vector<std::byte> (or equivalent).






      share|improve this answer























      • 4





        As original buffer data should not be not const, you should not have UB.

        – Jarod42
        Jun 3 at 7:56






      • 14





        And by then a good programmer goes: "Why the hell do I need a separate one-liner conversion function? Not only that, but this function named 'receive' doesn't actually perform any 'receiving'. Delete!"

        – screwnut
        Jun 3 at 8:32







      • 6





        @screwnut: To be fair, it is theoretically possible that receiver.data() waits on the reception to happen, or does something else beyond returning a member pointer.

        – einpoklum
        Jun 3 at 22:53






      • 9





        @screwnut: Then I'm a bad programmer; I'll keep the conversion in a separate function, even if it's a one liner, because I appreciate abstraction and do not like to repeat myself. If I later need to add some checks, some logging, etc... the function is right here and I don't have to hunt around the codebase for all instances of conversion.

        – Matthieu M.
        Jun 4 at 6:58






      • 5





        @screwnut: Prefer non-member non-friend functions.

        – Matthieu M.
        Jun 4 at 10:57















      64


















      You can completely avoid a manual memcpy by calling the appropriate constructor:



      std::string receive_data(const Receiver& receiver) 
      return receiver.data(), receiver.size();



      That even handles in a string.



      BTW, unless content is actually text, I would prefer std::vector<std::byte> (or equivalent).






      share|improve this answer























      • 4





        As original buffer data should not be not const, you should not have UB.

        – Jarod42
        Jun 3 at 7:56






      • 14





        And by then a good programmer goes: "Why the hell do I need a separate one-liner conversion function? Not only that, but this function named 'receive' doesn't actually perform any 'receiving'. Delete!"

        – screwnut
        Jun 3 at 8:32







      • 6





        @screwnut: To be fair, it is theoretically possible that receiver.data() waits on the reception to happen, or does something else beyond returning a member pointer.

        – einpoklum
        Jun 3 at 22:53






      • 9





        @screwnut: Then I'm a bad programmer; I'll keep the conversion in a separate function, even if it's a one liner, because I appreciate abstraction and do not like to repeat myself. If I later need to add some checks, some logging, etc... the function is right here and I don't have to hunt around the codebase for all instances of conversion.

        – Matthieu M.
        Jun 4 at 6:58






      • 5





        @screwnut: Prefer non-member non-friend functions.

        – Matthieu M.
        Jun 4 at 10:57













      64














      64










      64









      You can completely avoid a manual memcpy by calling the appropriate constructor:



      std::string receive_data(const Receiver& receiver) 
      return receiver.data(), receiver.size();



      That even handles in a string.



      BTW, unless content is actually text, I would prefer std::vector<std::byte> (or equivalent).






      share|improve this answer
















      You can completely avoid a manual memcpy by calling the appropriate constructor:



      std::string receive_data(const Receiver& receiver) 
      return receiver.data(), receiver.size();



      That even handles in a string.



      BTW, unless content is actually text, I would prefer std::vector<std::byte> (or equivalent).







      share|improve this answer















      share|improve this answer




      share|improve this answer








      edited Jun 6 at 12:16









      Peter Mortensen

      14.5k19 gold badges89 silver badges118 bronze badges




      14.5k19 gold badges89 silver badges118 bronze badges










      answered Jun 3 at 7:46









      Jarod42Jarod42

      133k12 gold badges117 silver badges210 bronze badges




      133k12 gold badges117 silver badges210 bronze badges










      • 4





        As original buffer data should not be not const, you should not have UB.

        – Jarod42
        Jun 3 at 7:56






      • 14





        And by then a good programmer goes: "Why the hell do I need a separate one-liner conversion function? Not only that, but this function named 'receive' doesn't actually perform any 'receiving'. Delete!"

        – screwnut
        Jun 3 at 8:32







      • 6





        @screwnut: To be fair, it is theoretically possible that receiver.data() waits on the reception to happen, or does something else beyond returning a member pointer.

        – einpoklum
        Jun 3 at 22:53






      • 9





        @screwnut: Then I'm a bad programmer; I'll keep the conversion in a separate function, even if it's a one liner, because I appreciate abstraction and do not like to repeat myself. If I later need to add some checks, some logging, etc... the function is right here and I don't have to hunt around the codebase for all instances of conversion.

        – Matthieu M.
        Jun 4 at 6:58






      • 5





        @screwnut: Prefer non-member non-friend functions.

        – Matthieu M.
        Jun 4 at 10:57












      • 4





        As original buffer data should not be not const, you should not have UB.

        – Jarod42
        Jun 3 at 7:56






      • 14





        And by then a good programmer goes: "Why the hell do I need a separate one-liner conversion function? Not only that, but this function named 'receive' doesn't actually perform any 'receiving'. Delete!"

        – screwnut
        Jun 3 at 8:32







      • 6





        @screwnut: To be fair, it is theoretically possible that receiver.data() waits on the reception to happen, or does something else beyond returning a member pointer.

        – einpoklum
        Jun 3 at 22:53






      • 9





        @screwnut: Then I'm a bad programmer; I'll keep the conversion in a separate function, even if it's a one liner, because I appreciate abstraction and do not like to repeat myself. If I later need to add some checks, some logging, etc... the function is right here and I don't have to hunt around the codebase for all instances of conversion.

        – Matthieu M.
        Jun 4 at 6:58






      • 5





        @screwnut: Prefer non-member non-friend functions.

        – Matthieu M.
        Jun 4 at 10:57







      4




      4





      As original buffer data should not be not const, you should not have UB.

      – Jarod42
      Jun 3 at 7:56





      As original buffer data should not be not const, you should not have UB.

      – Jarod42
      Jun 3 at 7:56




      14




      14





      And by then a good programmer goes: "Why the hell do I need a separate one-liner conversion function? Not only that, but this function named 'receive' doesn't actually perform any 'receiving'. Delete!"

      – screwnut
      Jun 3 at 8:32






      And by then a good programmer goes: "Why the hell do I need a separate one-liner conversion function? Not only that, but this function named 'receive' doesn't actually perform any 'receiving'. Delete!"

      – screwnut
      Jun 3 at 8:32





      6




      6





      @screwnut: To be fair, it is theoretically possible that receiver.data() waits on the reception to happen, or does something else beyond returning a member pointer.

      – einpoklum
      Jun 3 at 22:53





      @screwnut: To be fair, it is theoretically possible that receiver.data() waits on the reception to happen, or does something else beyond returning a member pointer.

      – einpoklum
      Jun 3 at 22:53




      9




      9





      @screwnut: Then I'm a bad programmer; I'll keep the conversion in a separate function, even if it's a one liner, because I appreciate abstraction and do not like to repeat myself. If I later need to add some checks, some logging, etc... the function is right here and I don't have to hunt around the codebase for all instances of conversion.

      – Matthieu M.
      Jun 4 at 6:58





      @screwnut: Then I'm a bad programmer; I'll keep the conversion in a separate function, even if it's a one liner, because I appreciate abstraction and do not like to repeat myself. If I later need to add some checks, some logging, etc... the function is right here and I don't have to hunt around the codebase for all instances of conversion.

      – Matthieu M.
      Jun 4 at 6:58




      5




      5





      @screwnut: Prefer non-member non-friend functions.

      – Matthieu M.
      Jun 4 at 10:57





      @screwnut: Prefer non-member non-friend functions.

      – Matthieu M.
      Jun 4 at 10:57











      9



















      Memcpy-ing to a const char pointer? AFAIK this does no harm as long as we know what we do, but is this good behavior and why?




      The current code may have undefined behavior, depending on the C++ version. To avoid undefined behavior in C++14 and below take the address of the first element. It yields a non-const pointer:



      buff.resize(size);
      memcpy(&buff[0], &receiver[0], size);




      I have recently seen a colleague of mine using std::string as a buffer...




      That was somewhat common in older code, especially circa C++03. There are several benefits and downsides to using a string like that. Depending on what you are doing with the code, std::vector can be a bit anemic, and you sometimes used a string instead and accepted the extra overhead of char_traits.



      For example, std::string is usually a faster container than std::vector on append, and you can't return std::vector from a function. (Or you could not do so in practice in C++98 because C++98 required the vector to be constructed in the function and copied out). Additionally, std::string allowed you to search with a richer assortment of member functions, like find_first_of and find_first_not_of. That was convenient when searching though arrays of bytes.



      I think what you really want/need is SGI's Rope class, but it never made it into the STL. It looks like GCC's libstdc++ may provide it.




      There a lengthy discussion about this being legal in C++14 and below:



      const char* dst_ptr = buff.data();
      const char* src_ptr = receiver.data();
      memcpy((char*) dst_ptr, src_ptr, size);


      I know for certain it is not safe in GCC. I once did something like this in some self tests and it resulted in a segfault:



      std::string buff("A");
      ...

      char* ptr = (char*)buff.data();
      size_t len = buff.size();

      ptr[0] ^= 1; // tamper with byte
      bool tampered = HMAC(key, ptr, len, mac);


      GCC put the single byte 'A' in register AL. The high 3-bytes were garbage, so the 32-bit register was 0xXXXXXX41. When I dereferenced at ptr[0], GCC dereferenced a garbage address 0xXXXXXX41.



      The two take-aways for me were, don't write half-ass self tests, and don't try to make data() a non-const pointer.






      share|improve this answer























      • 7





        Prefer std::copy for type-safety. It won't be slower.

        – Lightness Races in Orbit
        Jun 3 at 17:07






      • 3





        Seems like the only answer directly answering the question.

        – Keith
        Jun 4 at 0:59






      • 2





        "you can't return std::vector from a function. (Or you could not do so back in C++98 or C++03)" is wrong.

        – Ben Voigt
        Jun 4 at 2:38






      • 3





        And it has never been a legal optimization for a compiler to confuse an address with stored content. buff.data() cannot be a register containing 'A', it must be an address.

        – Ben Voigt
        Jun 4 at 2:40







      • 2





        @jww: Indeed, although you could avoid that copy with NRVO and a swap() call. But the copy would also be required of std::string. Small string optimization could make it a little better. I think some implementations tried to solve this using copy-on-write (for string, never allowed for vector) but even in C++98 and C++03 there were some specifications on std::string that couldn't be reasonable met by COW. Of course rvalue references and moves solved it neatly.

        – Ben Voigt
        Jun 4 at 3:01
















      9



















      Memcpy-ing to a const char pointer? AFAIK this does no harm as long as we know what we do, but is this good behavior and why?




      The current code may have undefined behavior, depending on the C++ version. To avoid undefined behavior in C++14 and below take the address of the first element. It yields a non-const pointer:



      buff.resize(size);
      memcpy(&buff[0], &receiver[0], size);




      I have recently seen a colleague of mine using std::string as a buffer...




      That was somewhat common in older code, especially circa C++03. There are several benefits and downsides to using a string like that. Depending on what you are doing with the code, std::vector can be a bit anemic, and you sometimes used a string instead and accepted the extra overhead of char_traits.



      For example, std::string is usually a faster container than std::vector on append, and you can't return std::vector from a function. (Or you could not do so in practice in C++98 because C++98 required the vector to be constructed in the function and copied out). Additionally, std::string allowed you to search with a richer assortment of member functions, like find_first_of and find_first_not_of. That was convenient when searching though arrays of bytes.



      I think what you really want/need is SGI's Rope class, but it never made it into the STL. It looks like GCC's libstdc++ may provide it.




      There a lengthy discussion about this being legal in C++14 and below:



      const char* dst_ptr = buff.data();
      const char* src_ptr = receiver.data();
      memcpy((char*) dst_ptr, src_ptr, size);


      I know for certain it is not safe in GCC. I once did something like this in some self tests and it resulted in a segfault:



      std::string buff("A");
      ...

      char* ptr = (char*)buff.data();
      size_t len = buff.size();

      ptr[0] ^= 1; // tamper with byte
      bool tampered = HMAC(key, ptr, len, mac);


      GCC put the single byte 'A' in register AL. The high 3-bytes were garbage, so the 32-bit register was 0xXXXXXX41. When I dereferenced at ptr[0], GCC dereferenced a garbage address 0xXXXXXX41.



      The two take-aways for me were, don't write half-ass self tests, and don't try to make data() a non-const pointer.






      share|improve this answer























      • 7





        Prefer std::copy for type-safety. It won't be slower.

        – Lightness Races in Orbit
        Jun 3 at 17:07






      • 3





        Seems like the only answer directly answering the question.

        – Keith
        Jun 4 at 0:59






      • 2





        "you can't return std::vector from a function. (Or you could not do so back in C++98 or C++03)" is wrong.

        – Ben Voigt
        Jun 4 at 2:38






      • 3





        And it has never been a legal optimization for a compiler to confuse an address with stored content. buff.data() cannot be a register containing 'A', it must be an address.

        – Ben Voigt
        Jun 4 at 2:40







      • 2





        @jww: Indeed, although you could avoid that copy with NRVO and a swap() call. But the copy would also be required of std::string. Small string optimization could make it a little better. I think some implementations tried to solve this using copy-on-write (for string, never allowed for vector) but even in C++98 and C++03 there were some specifications on std::string that couldn't be reasonable met by COW. Of course rvalue references and moves solved it neatly.

        – Ben Voigt
        Jun 4 at 3:01














      9














      9










      9










      Memcpy-ing to a const char pointer? AFAIK this does no harm as long as we know what we do, but is this good behavior and why?




      The current code may have undefined behavior, depending on the C++ version. To avoid undefined behavior in C++14 and below take the address of the first element. It yields a non-const pointer:



      buff.resize(size);
      memcpy(&buff[0], &receiver[0], size);




      I have recently seen a colleague of mine using std::string as a buffer...




      That was somewhat common in older code, especially circa C++03. There are several benefits and downsides to using a string like that. Depending on what you are doing with the code, std::vector can be a bit anemic, and you sometimes used a string instead and accepted the extra overhead of char_traits.



      For example, std::string is usually a faster container than std::vector on append, and you can't return std::vector from a function. (Or you could not do so in practice in C++98 because C++98 required the vector to be constructed in the function and copied out). Additionally, std::string allowed you to search with a richer assortment of member functions, like find_first_of and find_first_not_of. That was convenient when searching though arrays of bytes.



      I think what you really want/need is SGI's Rope class, but it never made it into the STL. It looks like GCC's libstdc++ may provide it.




      There a lengthy discussion about this being legal in C++14 and below:



      const char* dst_ptr = buff.data();
      const char* src_ptr = receiver.data();
      memcpy((char*) dst_ptr, src_ptr, size);


      I know for certain it is not safe in GCC. I once did something like this in some self tests and it resulted in a segfault:



      std::string buff("A");
      ...

      char* ptr = (char*)buff.data();
      size_t len = buff.size();

      ptr[0] ^= 1; // tamper with byte
      bool tampered = HMAC(key, ptr, len, mac);


      GCC put the single byte 'A' in register AL. The high 3-bytes were garbage, so the 32-bit register was 0xXXXXXX41. When I dereferenced at ptr[0], GCC dereferenced a garbage address 0xXXXXXX41.



      The two take-aways for me were, don't write half-ass self tests, and don't try to make data() a non-const pointer.






      share|improve this answer

















      Memcpy-ing to a const char pointer? AFAIK this does no harm as long as we know what we do, but is this good behavior and why?




      The current code may have undefined behavior, depending on the C++ version. To avoid undefined behavior in C++14 and below take the address of the first element. It yields a non-const pointer:



      buff.resize(size);
      memcpy(&buff[0], &receiver[0], size);




      I have recently seen a colleague of mine using std::string as a buffer...




      That was somewhat common in older code, especially circa C++03. There are several benefits and downsides to using a string like that. Depending on what you are doing with the code, std::vector can be a bit anemic, and you sometimes used a string instead and accepted the extra overhead of char_traits.



      For example, std::string is usually a faster container than std::vector on append, and you can't return std::vector from a function. (Or you could not do so in practice in C++98 because C++98 required the vector to be constructed in the function and copied out). Additionally, std::string allowed you to search with a richer assortment of member functions, like find_first_of and find_first_not_of. That was convenient when searching though arrays of bytes.



      I think what you really want/need is SGI's Rope class, but it never made it into the STL. It looks like GCC's libstdc++ may provide it.




      There a lengthy discussion about this being legal in C++14 and below:



      const char* dst_ptr = buff.data();
      const char* src_ptr = receiver.data();
      memcpy((char*) dst_ptr, src_ptr, size);


      I know for certain it is not safe in GCC. I once did something like this in some self tests and it resulted in a segfault:



      std::string buff("A");
      ...

      char* ptr = (char*)buff.data();
      size_t len = buff.size();

      ptr[0] ^= 1; // tamper with byte
      bool tampered = HMAC(key, ptr, len, mac);


      GCC put the single byte 'A' in register AL. The high 3-bytes were garbage, so the 32-bit register was 0xXXXXXX41. When I dereferenced at ptr[0], GCC dereferenced a garbage address 0xXXXXXX41.



      The two take-aways for me were, don't write half-ass self tests, and don't try to make data() a non-const pointer.







      share|improve this answer















      share|improve this answer




      share|improve this answer








      edited Jun 4 at 7:57









      Toby Speight

      18.9k13 gold badges49 silver badges73 bronze badges




      18.9k13 gold badges49 silver badges73 bronze badges










      answered Jun 3 at 17:04









      jwwjww

      58.6k46 gold badges262 silver badges571 bronze badges




      58.6k46 gold badges262 silver badges571 bronze badges










      • 7





        Prefer std::copy for type-safety. It won't be slower.

        – Lightness Races in Orbit
        Jun 3 at 17:07






      • 3





        Seems like the only answer directly answering the question.

        – Keith
        Jun 4 at 0:59






      • 2





        "you can't return std::vector from a function. (Or you could not do so back in C++98 or C++03)" is wrong.

        – Ben Voigt
        Jun 4 at 2:38






      • 3





        And it has never been a legal optimization for a compiler to confuse an address with stored content. buff.data() cannot be a register containing 'A', it must be an address.

        – Ben Voigt
        Jun 4 at 2:40







      • 2





        @jww: Indeed, although you could avoid that copy with NRVO and a swap() call. But the copy would also be required of std::string. Small string optimization could make it a little better. I think some implementations tried to solve this using copy-on-write (for string, never allowed for vector) but even in C++98 and C++03 there were some specifications on std::string that couldn't be reasonable met by COW. Of course rvalue references and moves solved it neatly.

        – Ben Voigt
        Jun 4 at 3:01













      • 7





        Prefer std::copy for type-safety. It won't be slower.

        – Lightness Races in Orbit
        Jun 3 at 17:07






      • 3





        Seems like the only answer directly answering the question.

        – Keith
        Jun 4 at 0:59






      • 2





        "you can't return std::vector from a function. (Or you could not do so back in C++98 or C++03)" is wrong.

        – Ben Voigt
        Jun 4 at 2:38






      • 3





        And it has never been a legal optimization for a compiler to confuse an address with stored content. buff.data() cannot be a register containing 'A', it must be an address.

        – Ben Voigt
        Jun 4 at 2:40







      • 2





        @jww: Indeed, although you could avoid that copy with NRVO and a swap() call. But the copy would also be required of std::string. Small string optimization could make it a little better. I think some implementations tried to solve this using copy-on-write (for string, never allowed for vector) but even in C++98 and C++03 there were some specifications on std::string that couldn't be reasonable met by COW. Of course rvalue references and moves solved it neatly.

        – Ben Voigt
        Jun 4 at 3:01








      7




      7





      Prefer std::copy for type-safety. It won't be slower.

      – Lightness Races in Orbit
      Jun 3 at 17:07





      Prefer std::copy for type-safety. It won't be slower.

      – Lightness Races in Orbit
      Jun 3 at 17:07




      3




      3





      Seems like the only answer directly answering the question.

      – Keith
      Jun 4 at 0:59





      Seems like the only answer directly answering the question.

      – Keith
      Jun 4 at 0:59




      2




      2





      "you can't return std::vector from a function. (Or you could not do so back in C++98 or C++03)" is wrong.

      – Ben Voigt
      Jun 4 at 2:38





      "you can't return std::vector from a function. (Or you could not do so back in C++98 or C++03)" is wrong.

      – Ben Voigt
      Jun 4 at 2:38




      3




      3





      And it has never been a legal optimization for a compiler to confuse an address with stored content. buff.data() cannot be a register containing 'A', it must be an address.

      – Ben Voigt
      Jun 4 at 2:40






      And it has never been a legal optimization for a compiler to confuse an address with stored content. buff.data() cannot be a register containing 'A', it must be an address.

      – Ben Voigt
      Jun 4 at 2:40





      2




      2





      @jww: Indeed, although you could avoid that copy with NRVO and a swap() call. But the copy would also be required of std::string. Small string optimization could make it a little better. I think some implementations tried to solve this using copy-on-write (for string, never allowed for vector) but even in C++98 and C++03 there were some specifications on std::string that couldn't be reasonable met by COW. Of course rvalue references and moves solved it neatly.

      – Ben Voigt
      Jun 4 at 3:01






      @jww: Indeed, although you could avoid that copy with NRVO and a swap() call. But the copy would also be required of std::string. Small string optimization could make it a little better. I think some implementations tried to solve this using copy-on-write (for string, never allowed for vector) but even in C++98 and C++03 there were some specifications on std::string that couldn't be reasonable met by COW. Of course rvalue references and moves solved it neatly.

      – Ben Voigt
      Jun 4 at 3:01












      7


















      From C++17, data can return a non const char *.



      Draft n4659 declares at [string.accessors]:




      const charT* c_str() const noexcept;
      const charT* data() const noexcept;
      ....
      charT* data() noexcept;






      share|improve this answer





















      • 8





        @SergeBallesta - Removing a const qualifier is not UB. Modifying a const object is UB. The object in question is not const.

        – StoryTeller
        Jun 3 at 7:59






      • 6





        @SergeBallesta - Seriously? And how do you reconcile that with &str[0] being a non-const pointer to the very same buffer? The object is guaranteed not to be const. The core rules of the language still apply, even to pointers returned from library types, ergo, no UB.

        – StoryTeller
        Jun 3 at 8:05







      • 4





        @Jarod42: I agree that I am nitpicking here, but the library could expect the buffer not be be changed, and later reuse a cached version. Coming for old K&R C I am now frightened by optimizing compilers and very cautious for constness and strict aliasing.

        – Serge Ballesta
        Jun 3 at 8:07







      • 8





        @StoryTeller Serge is correct that "Modifying the character array accessed through the const overload of data has undefined behavior." according to cppreference and the standard.

        – Max Langhof
        Jun 3 at 8:16







      • 4





        (For completeness, here is the C++11 wording: timsong-cpp.github.io/cppwp/n3337/string.ops#string.accessors-3)

        – Max Langhof
        Jun 3 at 8:22















      7


















      From C++17, data can return a non const char *.



      Draft n4659 declares at [string.accessors]:




      const charT* c_str() const noexcept;
      const charT* data() const noexcept;
      ....
      charT* data() noexcept;






      share|improve this answer





















      • 8





        @SergeBallesta - Removing a const qualifier is not UB. Modifying a const object is UB. The object in question is not const.

        – StoryTeller
        Jun 3 at 7:59






      • 6





        @SergeBallesta - Seriously? And how do you reconcile that with &str[0] being a non-const pointer to the very same buffer? The object is guaranteed not to be const. The core rules of the language still apply, even to pointers returned from library types, ergo, no UB.

        – StoryTeller
        Jun 3 at 8:05







      • 4





        @Jarod42: I agree that I am nitpicking here, but the library could expect the buffer not be be changed, and later reuse a cached version. Coming for old K&R C I am now frightened by optimizing compilers and very cautious for constness and strict aliasing.

        – Serge Ballesta
        Jun 3 at 8:07







      • 8





        @StoryTeller Serge is correct that "Modifying the character array accessed through the const overload of data has undefined behavior." according to cppreference and the standard.

        – Max Langhof
        Jun 3 at 8:16







      • 4





        (For completeness, here is the C++11 wording: timsong-cpp.github.io/cppwp/n3337/string.ops#string.accessors-3)

        – Max Langhof
        Jun 3 at 8:22













      7














      7










      7









      From C++17, data can return a non const char *.



      Draft n4659 declares at [string.accessors]:




      const charT* c_str() const noexcept;
      const charT* data() const noexcept;
      ....
      charT* data() noexcept;






      share|improve this answer














      From C++17, data can return a non const char *.



      Draft n4659 declares at [string.accessors]:




      const charT* c_str() const noexcept;
      const charT* data() const noexcept;
      ....
      charT* data() noexcept;







      share|improve this answer













      share|improve this answer




      share|improve this answer










      answered Jun 3 at 7:42









      Serge BallestaSerge Ballesta

      90.2k9 gold badges71 silver badges149 bronze badges




      90.2k9 gold badges71 silver badges149 bronze badges










      • 8





        @SergeBallesta - Removing a const qualifier is not UB. Modifying a const object is UB. The object in question is not const.

        – StoryTeller
        Jun 3 at 7:59






      • 6





        @SergeBallesta - Seriously? And how do you reconcile that with &str[0] being a non-const pointer to the very same buffer? The object is guaranteed not to be const. The core rules of the language still apply, even to pointers returned from library types, ergo, no UB.

        – StoryTeller
        Jun 3 at 8:05







      • 4





        @Jarod42: I agree that I am nitpicking here, but the library could expect the buffer not be be changed, and later reuse a cached version. Coming for old K&R C I am now frightened by optimizing compilers and very cautious for constness and strict aliasing.

        – Serge Ballesta
        Jun 3 at 8:07







      • 8





        @StoryTeller Serge is correct that "Modifying the character array accessed through the const overload of data has undefined behavior." according to cppreference and the standard.

        – Max Langhof
        Jun 3 at 8:16







      • 4





        (For completeness, here is the C++11 wording: timsong-cpp.github.io/cppwp/n3337/string.ops#string.accessors-3)

        – Max Langhof
        Jun 3 at 8:22












      • 8





        @SergeBallesta - Removing a const qualifier is not UB. Modifying a const object is UB. The object in question is not const.

        – StoryTeller
        Jun 3 at 7:59






      • 6





        @SergeBallesta - Seriously? And how do you reconcile that with &str[0] being a non-const pointer to the very same buffer? The object is guaranteed not to be const. The core rules of the language still apply, even to pointers returned from library types, ergo, no UB.

        – StoryTeller
        Jun 3 at 8:05







      • 4





        @Jarod42: I agree that I am nitpicking here, but the library could expect the buffer not be be changed, and later reuse a cached version. Coming for old K&R C I am now frightened by optimizing compilers and very cautious for constness and strict aliasing.

        – Serge Ballesta
        Jun 3 at 8:07







      • 8





        @StoryTeller Serge is correct that "Modifying the character array accessed through the const overload of data has undefined behavior." according to cppreference and the standard.

        – Max Langhof
        Jun 3 at 8:16







      • 4





        (For completeness, here is the C++11 wording: timsong-cpp.github.io/cppwp/n3337/string.ops#string.accessors-3)

        – Max Langhof
        Jun 3 at 8:22







      8




      8





      @SergeBallesta - Removing a const qualifier is not UB. Modifying a const object is UB. The object in question is not const.

      – StoryTeller
      Jun 3 at 7:59





      @SergeBallesta - Removing a const qualifier is not UB. Modifying a const object is UB. The object in question is not const.

      – StoryTeller
      Jun 3 at 7:59




      6




      6





      @SergeBallesta - Seriously? And how do you reconcile that with &str[0] being a non-const pointer to the very same buffer? The object is guaranteed not to be const. The core rules of the language still apply, even to pointers returned from library types, ergo, no UB.

      – StoryTeller
      Jun 3 at 8:05






      @SergeBallesta - Seriously? And how do you reconcile that with &str[0] being a non-const pointer to the very same buffer? The object is guaranteed not to be const. The core rules of the language still apply, even to pointers returned from library types, ergo, no UB.

      – StoryTeller
      Jun 3 at 8:05





      4




      4





      @Jarod42: I agree that I am nitpicking here, but the library could expect the buffer not be be changed, and later reuse a cached version. Coming for old K&R C I am now frightened by optimizing compilers and very cautious for constness and strict aliasing.

      – Serge Ballesta
      Jun 3 at 8:07






      @Jarod42: I agree that I am nitpicking here, but the library could expect the buffer not be be changed, and later reuse a cached version. Coming for old K&R C I am now frightened by optimizing compilers and very cautious for constness and strict aliasing.

      – Serge Ballesta
      Jun 3 at 8:07





      8




      8





      @StoryTeller Serge is correct that "Modifying the character array accessed through the const overload of data has undefined behavior." according to cppreference and the standard.

      – Max Langhof
      Jun 3 at 8:16






      @StoryTeller Serge is correct that "Modifying the character array accessed through the const overload of data has undefined behavior." according to cppreference and the standard.

      – Max Langhof
      Jun 3 at 8:16





      4




      4





      (For completeness, here is the C++11 wording: timsong-cpp.github.io/cppwp/n3337/string.ops#string.accessors-3)

      – Max Langhof
      Jun 3 at 8:22





      (For completeness, here is the C++11 wording: timsong-cpp.github.io/cppwp/n3337/string.ops#string.accessors-3)

      – Max Langhof
      Jun 3 at 8:22











      7


















      The code is unnecessary, considering that



      std::string receive_data(const Receiver& receiver) 
      std::string buff;
      int size = receiver.size();
      if (size > 0)
      buff.assign(receiver.data(), size);

      return buff;



      will do exactly the same.






      share|improve this answer





















      • 2





        You can cut even more code; the if is also unnecessary. assign will be a no-op then. But continue to unnecessary remove code, and you end up with Jarod42's answer. None of these lines are necessary, as std::string already has an appropriate constructor.

        – MSalters
        Jun 4 at 11:32











      • @MSalters I prefer not to assume things that are not given. What if receiver.size() can return negative values?

        – Kit.
        Jun 5 at 14:02











      • That would be rather unexpected, given that sizes are typically a size_t and therefore unsigned. That does show a possible problem with your code: it might suffer from signed integer overflow, which is undefined behavior. And that's on a code path which handles input, so this may constitute an externally exploitable vulnerability.

        – MSalters
        Jun 6 at 8:53











      • @MSalters True, Jarod42's changes could introduce an externally exploitable vulnerability. They could also introduce crashes if receiver.data() is UB when receiver.size() is zero.

        – Kit.
        Jun 7 at 7:41















      7


















      The code is unnecessary, considering that



      std::string receive_data(const Receiver& receiver) 
      std::string buff;
      int size = receiver.size();
      if (size > 0)
      buff.assign(receiver.data(), size);

      return buff;



      will do exactly the same.






      share|improve this answer





















      • 2





        You can cut even more code; the if is also unnecessary. assign will be a no-op then. But continue to unnecessary remove code, and you end up with Jarod42's answer. None of these lines are necessary, as std::string already has an appropriate constructor.

        – MSalters
        Jun 4 at 11:32











      • @MSalters I prefer not to assume things that are not given. What if receiver.size() can return negative values?

        – Kit.
        Jun 5 at 14:02











      • That would be rather unexpected, given that sizes are typically a size_t and therefore unsigned. That does show a possible problem with your code: it might suffer from signed integer overflow, which is undefined behavior. And that's on a code path which handles input, so this may constitute an externally exploitable vulnerability.

        – MSalters
        Jun 6 at 8:53











      • @MSalters True, Jarod42's changes could introduce an externally exploitable vulnerability. They could also introduce crashes if receiver.data() is UB when receiver.size() is zero.

        – Kit.
        Jun 7 at 7:41













      7














      7










      7









      The code is unnecessary, considering that



      std::string receive_data(const Receiver& receiver) 
      std::string buff;
      int size = receiver.size();
      if (size > 0)
      buff.assign(receiver.data(), size);

      return buff;



      will do exactly the same.






      share|improve this answer














      The code is unnecessary, considering that



      std::string receive_data(const Receiver& receiver) 
      std::string buff;
      int size = receiver.size();
      if (size > 0)
      buff.assign(receiver.data(), size);

      return buff;



      will do exactly the same.







      share|improve this answer













      share|improve this answer




      share|improve this answer










      answered Jun 3 at 7:49









      Kit.Kit.

      1,1997 silver badges9 bronze badges




      1,1997 silver badges9 bronze badges










      • 2





        You can cut even more code; the if is also unnecessary. assign will be a no-op then. But continue to unnecessary remove code, and you end up with Jarod42's answer. None of these lines are necessary, as std::string already has an appropriate constructor.

        – MSalters
        Jun 4 at 11:32











      • @MSalters I prefer not to assume things that are not given. What if receiver.size() can return negative values?

        – Kit.
        Jun 5 at 14:02











      • That would be rather unexpected, given that sizes are typically a size_t and therefore unsigned. That does show a possible problem with your code: it might suffer from signed integer overflow, which is undefined behavior. And that's on a code path which handles input, so this may constitute an externally exploitable vulnerability.

        – MSalters
        Jun 6 at 8:53











      • @MSalters True, Jarod42's changes could introduce an externally exploitable vulnerability. They could also introduce crashes if receiver.data() is UB when receiver.size() is zero.

        – Kit.
        Jun 7 at 7:41












      • 2





        You can cut even more code; the if is also unnecessary. assign will be a no-op then. But continue to unnecessary remove code, and you end up with Jarod42's answer. None of these lines are necessary, as std::string already has an appropriate constructor.

        – MSalters
        Jun 4 at 11:32











      • @MSalters I prefer not to assume things that are not given. What if receiver.size() can return negative values?

        – Kit.
        Jun 5 at 14:02











      • That would be rather unexpected, given that sizes are typically a size_t and therefore unsigned. That does show a possible problem with your code: it might suffer from signed integer overflow, which is undefined behavior. And that's on a code path which handles input, so this may constitute an externally exploitable vulnerability.

        – MSalters
        Jun 6 at 8:53











      • @MSalters True, Jarod42's changes could introduce an externally exploitable vulnerability. They could also introduce crashes if receiver.data() is UB when receiver.size() is zero.

        – Kit.
        Jun 7 at 7:41







      2




      2





      You can cut even more code; the if is also unnecessary. assign will be a no-op then. But continue to unnecessary remove code, and you end up with Jarod42's answer. None of these lines are necessary, as std::string already has an appropriate constructor.

      – MSalters
      Jun 4 at 11:32





      You can cut even more code; the if is also unnecessary. assign will be a no-op then. But continue to unnecessary remove code, and you end up with Jarod42's answer. None of these lines are necessary, as std::string already has an appropriate constructor.

      – MSalters
      Jun 4 at 11:32













      @MSalters I prefer not to assume things that are not given. What if receiver.size() can return negative values?

      – Kit.
      Jun 5 at 14:02





      @MSalters I prefer not to assume things that are not given. What if receiver.size() can return negative values?

      – Kit.
      Jun 5 at 14:02













      That would be rather unexpected, given that sizes are typically a size_t and therefore unsigned. That does show a possible problem with your code: it might suffer from signed integer overflow, which is undefined behavior. And that's on a code path which handles input, so this may constitute an externally exploitable vulnerability.

      – MSalters
      Jun 6 at 8:53





      That would be rather unexpected, given that sizes are typically a size_t and therefore unsigned. That does show a possible problem with your code: it might suffer from signed integer overflow, which is undefined behavior. And that's on a code path which handles input, so this may constitute an externally exploitable vulnerability.

      – MSalters
      Jun 6 at 8:53













      @MSalters True, Jarod42's changes could introduce an externally exploitable vulnerability. They could also introduce crashes if receiver.data() is UB when receiver.size() is zero.

      – Kit.
      Jun 7 at 7:41





      @MSalters True, Jarod42's changes could introduce an externally exploitable vulnerability. They could also introduce crashes if receiver.data() is UB when receiver.size() is zero.

      – Kit.
      Jun 7 at 7:41











      5


















      The big optimization opportunity I would investigate here is: Receiver appears to be some kind of container that supports .data() and .size(). If you can consume it, and pass it in as a rvalue reference Receiver&&, you might be able to use move semantics without making any copies at all! If it’s got an iterator interface, you could use those for range-based constructors or std::move() from <algorithm>.



      In C++17 (as Serge Ballesta and others have mentioned), std::string::data() returns a pointer to non-const data. A std::string has been guaranteed to store all its data contiguously for years.



      The code as written smells a bit, although it’s not really the programmer’s fault: those hacks were necessary at the time. Today, you should at least change the type of dst_ptr from const char* to char* and remove the cast in the first argument to memcpy(). You could also reserve() a number of bytes for the buffer and then use a STL function to move the data.



      As others have mentioned, a std::vector or std::unique_ptr would be a more natural data structure to use here.






      share|improve this answer
































        5


















        The big optimization opportunity I would investigate here is: Receiver appears to be some kind of container that supports .data() and .size(). If you can consume it, and pass it in as a rvalue reference Receiver&&, you might be able to use move semantics without making any copies at all! If it’s got an iterator interface, you could use those for range-based constructors or std::move() from <algorithm>.



        In C++17 (as Serge Ballesta and others have mentioned), std::string::data() returns a pointer to non-const data. A std::string has been guaranteed to store all its data contiguously for years.



        The code as written smells a bit, although it’s not really the programmer’s fault: those hacks were necessary at the time. Today, you should at least change the type of dst_ptr from const char* to char* and remove the cast in the first argument to memcpy(). You could also reserve() a number of bytes for the buffer and then use a STL function to move the data.



        As others have mentioned, a std::vector or std::unique_ptr would be a more natural data structure to use here.






        share|improve this answer






























          5














          5










          5









          The big optimization opportunity I would investigate here is: Receiver appears to be some kind of container that supports .data() and .size(). If you can consume it, and pass it in as a rvalue reference Receiver&&, you might be able to use move semantics without making any copies at all! If it’s got an iterator interface, you could use those for range-based constructors or std::move() from <algorithm>.



          In C++17 (as Serge Ballesta and others have mentioned), std::string::data() returns a pointer to non-const data. A std::string has been guaranteed to store all its data contiguously for years.



          The code as written smells a bit, although it’s not really the programmer’s fault: those hacks were necessary at the time. Today, you should at least change the type of dst_ptr from const char* to char* and remove the cast in the first argument to memcpy(). You could also reserve() a number of bytes for the buffer and then use a STL function to move the data.



          As others have mentioned, a std::vector or std::unique_ptr would be a more natural data structure to use here.






          share|improve this answer
















          The big optimization opportunity I would investigate here is: Receiver appears to be some kind of container that supports .data() and .size(). If you can consume it, and pass it in as a rvalue reference Receiver&&, you might be able to use move semantics without making any copies at all! If it’s got an iterator interface, you could use those for range-based constructors or std::move() from <algorithm>.



          In C++17 (as Serge Ballesta and others have mentioned), std::string::data() returns a pointer to non-const data. A std::string has been guaranteed to store all its data contiguously for years.



          The code as written smells a bit, although it’s not really the programmer’s fault: those hacks were necessary at the time. Today, you should at least change the type of dst_ptr from const char* to char* and remove the cast in the first argument to memcpy(). You could also reserve() a number of bytes for the buffer and then use a STL function to move the data.



          As others have mentioned, a std::vector or std::unique_ptr would be a more natural data structure to use here.







          share|improve this answer















          share|improve this answer




          share|improve this answer








          edited Jun 4 at 17:53

























          answered Jun 3 at 21:29









          DavislorDavislor

          10.4k2 gold badges18 silver badges30 bronze badges




          10.4k2 gold badges18 silver badges30 bronze badges
























              4


















              One downside is performance.
              The .resize method will default-initialize all the new byte locations to 0.
              That initialization is unnecessary if you're then going to overwrite the 0s with other data.






              share|improve this answer






























                4


















                One downside is performance.
                The .resize method will default-initialize all the new byte locations to 0.
                That initialization is unnecessary if you're then going to overwrite the 0s with other data.






                share|improve this answer




























                  4














                  4










                  4









                  One downside is performance.
                  The .resize method will default-initialize all the new byte locations to 0.
                  That initialization is unnecessary if you're then going to overwrite the 0s with other data.






                  share|improve this answer














                  One downside is performance.
                  The .resize method will default-initialize all the new byte locations to 0.
                  That initialization is unnecessary if you're then going to overwrite the 0s with other data.







                  share|improve this answer













                  share|improve this answer




                  share|improve this answer










                  answered Jun 5 at 21:40









                  WaxratWaxrat

                  1813 bronze badges




                  1813 bronze badges































                      draft saved

                      draft discarded















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56422913%2fare-there-downsides-to-using-stdstring-as-a-buffer%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown









                      Popular posts from this blog

                      Tamil (spriik) Luke uk diar | Nawigatjuun

                      Align equal signs while including text over equalitiesAMS align: left aligned text/math plus multicolumn alignmentMultiple alignmentsAligning equations in multiple placesNumbering and aligning an equation with multiple columnsHow to align one equation with another multline equationUsing \ in environments inside the begintabularxNumber equations and preserving alignment of equal signsHow can I align equations to the left and to the right?Double equation alignment problem within align enviromentAligned within align: Why are they right-aligned?

                      Where does the image of a data connector as a sharp metal spike originate from?Where does the concept of infected people turning into zombies only after death originate from?Where does the motif of a reanimated human head originate?Where did the notion that Dragons could speak originate?Where does the archetypal image of the 'Grey' alien come from?Where did the suffix '-Man' originate?Where does the notion of being injured or killed by an illusion originate?Where did the term “sophont” originate?Where does the trope of magic spells being driven by advanced technology originate from?Where did the term “the living impaired” originate?