0

Suppose I'm calling a function which will populate a given buffer with some data: populate_buffer(char *buf, size_t buflen);

I want this filled data to finally end up in std::string. I have 2 approaches...

Approach 1:

char mybuf[32];
populate_buffer(mybuf, 32);
std::string mystr(mybuf, 32);

Approach 2:

std::string mystr;
mystr.resize(32);
populate_buffer(mystr.data(), 32);

What is more efficient?

Mat
  • 202,337
  • 40
  • 393
  • 406
ravinsp
  • 4,150
  • 2
  • 32
  • 43
  • 2
    The best way to find out is to crank up the optimizer and profile. Run a few million or billion iterations and see what takes longer. It's hard to say exactly what the code will look like after the optimizer's done with it, so It's often helpful to program in terms of the behaviour you want and let the compiler figure out what instructions are needed rather than sweating over little details. Write the simplest code that precisely describes what you want to happen and then test to ensure it meets your performance needs. Complicate the code as necessary. – user4581301 Oct 15 '19 at 17:13
  • @OP Who knows? Maybe after the optimizer is done with it, Approach 2 would look like Approach 1. Remember that the C++ code you write is a description of what you want to happen. The actual code that gets generated to do the job is a different story, and may not look anything like the original C++ high-level code. – PaulMcKenzie Oct 15 '19 at 17:25
  • 1
    Looking at the [assembly](https://godbolt.org/z/84P3me) of clang, approach 1 takes 27 instructions while approach 2 takes only 19 with `populate_buffer` beeing a black box. Looks like the `resize()` is optimized away, so approach 2 should be faster. – Timo Oct 15 '19 at 17:26
  • 1
    @Timo _approach 2 should be faster_ I would just clarify that this statement is only valid for your experiment. You cannot make any generic conslusions here. If a compiler saw the definition of `poplate_buffer`, the result might be different. And it can also heavily depend on what `populate_buffer` actually does. – Daniel Langr Oct 15 '19 at 17:29
  • 1
    @DanielLangr yes that's why this is not an answer and I explicitly described the parameters of the observation. – Timo Oct 15 '19 at 17:30
  • Thanks for all your comments! I was also inclining towards Approach 2 but I see that it can depend on the `populate_buffer()` implementation as well. In my case `populate_buffer()` represents various functions of similar nature available in different libraries. It could mean fd `read()` in linux or libsodium `crypto_sign_keypair` or more. Maybe there won't be a specific answer. But I'll go with Approach2 for general case. – ravinsp Oct 15 '19 at 17:35
  • `std::string::data()` returns a `const char*` so you have to do a `const_cast` for the code to compile cleanly. And const_casting a non-const variable is undefined behaviour. See https://stackoverflow.com/questions/19554841/how-to-use-const-cast/19554871. – Pibben Oct 16 '19 at 11:32
  • @Pibben `string::data()` returns `char*` since C++17. Also using `const_cast` on its own to remove or add constness doesn't result in UB. But it is UB to access a const object via a non-const path. This effectivly means `const_cast`ing an actually const object is bad, not the other way around. – Timo Oct 16 '19 at 16:49

0 Answers0