Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between std::string(size, '\0') and s.resize(size)?

Tags:

c++

c++14

Unlike std::vector, std::string does not provide a unary constructor that takes a size:

std::string s(size); // ERROR

Is there any difference between:

std::string s(size, '\0');

and

std::string s;
s.resize(size);

in terms of their performance on common implementations?

Will resize initialize the string to all zero characters or will it leave them an unspecified value?

If all zero, is there any way to construct a string of a given size, but leave the characters with an unspecified value?

like image 935
Andrew Tomazos Avatar asked Jul 29 '16 20:07

Andrew Tomazos


4 Answers

There is a difference, as in std::string s(size, '\0');, all of the memory needed for the string can be allocated at once. However, with the second example, if size is greater than the amount of characters stored for small string optimization, an extra allocation may have to be performed, although this is implementation defined, and will definitely not be more performant in that regard in a standard-compliant C++ 17 implementation. However, the first example is more consise, and may be more performant, so it is probably preferable. When calling s.resize(size);, all new characters will be initialized with char's default constructor, aka '\0'. There is no way to initialize a string with unspecified values.

like image 179
DeepCoder Avatar answered Oct 07 '22 07:10

DeepCoder


The actual answer would be implementation-based, but I'm fairly sure that std::string s(size, '\0'); is faster.

std::string s;
s.resize(size);

According to the documentation for std::string.

1) Default constructor. Constructs empty string (zero size and unspecified capacity).

The default constructor will create a string with an "unspecified capacity". My sense here is that the implementation is free to determine a default capacity, probably in the realm of 10-15 characters (totally speculation).

Then in the next line, you will reallocate the memory (resize) with the new size if the size is greater than the current capacity. This is probably not what you want!

If you really want to find out definitively, you can run a profiler on the two methods.

like image 28
Colin Basnett Avatar answered Oct 07 '22 06:10

Colin Basnett


There is already a good answer from DeepCoder.

For the records however, I'd like to point out that strings (as for vectors) there are two distinct notions:

  • the size(): it's the number of actual (i.e. meaningful) characters in the string. You can change it using resize() (to which you can provide a second parameter to say what char you want to use as filler if it should be other than '\0')
  • the capacity(): it's the number of characters allocated to the string. Its at least the size but can be more. You can increase it with reserve()

If you're worried about allocation performance, I believe it's better to play with the capacity. The size should really be kept for real chars in the string not for padding chars.

By the way, more generally, s.resize(n) is the same as s.resize(n, char()). So if you'd like to fill it on the same way at construction, you could consider string s(n, char()). But as long as you don't use basic_string<T> for T being different from characters, your '\0' just does the trick.

like image 2
Christophe Avatar answered Oct 07 '22 05:10

Christophe


Resize does not leave elements uninitialized. According to the documentation: http://en.cppreference.com/w/cpp/string/basic_string/resize

s.resize(size) will value-initialize each appended character. That will cause each element of the resized string to be initialized to '\0'.

You would have to measure the performance difference of your specific C++ implementation to really decide if there's a worthwhile difference or not.

After looking at the machine generated by Visual C++ for an optimized build, I can tell you the amount of code for either version is similar. What seems counter intuitive is that the resize() version measured faster for me. Still, you should check your own compiler and standard library.

like image 1
ChrisG0x20 Avatar answered Oct 07 '22 07:10

ChrisG0x20