Felix Dombek
Felix Dombek

Reputation: 14372

Construct std::string from up to X characters, stopping at null char

I am reading strings from a structure in a file where each string has a fixed length, with '\0' padding. They are not zero-terminated if the stored string needs the whole length.

I'm currently constructing std::strings out of those like this:

// char MyString[1000];
std::string stdmystring(MyString, ARRAYSIZE(MyString));

However, this copies the padding, too. I could trim the string now, but is there an elegant and quick way to prevent the copying in the first place?

Speed is more important than space, because this runs in a loop.

Upvotes: 6

Views: 1572

Answers (3)

Mark B
Mark B

Reputation: 96281

I think the most straightforward way is to overallocate your internal MyString array by one byte, always null terminate that final byte, and use the C-string constructor of std::string. (Keep in mind that most likely your process will be I/O bound on the file so whatever algorithm the C-string constructor uses should be fine).

Upvotes: 0

Abstraction
Abstraction

Reputation: 511

Well If size is not a problem one potential way to do it is to create an empty std::string then use reserve() to pre-allocate the space potentially needed and then add each char until you come across '\0'.

std::string stdmystring;
stdmystring.reserve(MyString_MAX_SIZE) ;
for(size_t i=0;i<MyString_MAX_SIZE && MyString[i]!='\0';++i);
stdmystring+=MyString[i];

reserve() garanties you one memory allocation since you know the max_size and the string will never get larger than that.

The calls to += operator function will probably be inlined but it still has to check that the string has the needed capacity which is wasteful in your case. Infact this could be the same or worse than simply using strlen to find the exact length of the string first so you have to test it.

Upvotes: 2

Useless
Useless

Reputation: 67772

Simple solutions are:

  1. Just calculate the correct length first

    • either use strnlen as Dieter suggested
    • or std::find(MyString,MyString+ARRAYSIZE(MyString),'\0') which IME isn't any slower

    note that if your string fits in cache, that will likely dominate the extra loop cost

  2. reserve the max string size (you did say space was less important), and write a loop appending characters until you exhaust the width or hit a nul (like copy_until)

  3. actually create a max-size string initialized with nuls, strncpy into it, and optionally erase unused nuls if you want the size to be correct

The second option uses only a single loop, while the third notionally uses two (it in the string ctor, and then in the copy). However, the push_back of each character seems more expensive than the simple character assignment, so I wouldn't be surprised if #3 were faster in reality. Profile and see!

Upvotes: 2

Related Questions