saleph
saleph

Reputation: 149

Effective construction std::string from std::unordered_set<char>

I have an unordered_set of chars

std::unordered_set<char> u_setAlphabet;

Then I want to get a content from the set as std::string. My implementation now looks like this:

std::string getAlphabet() {
    std::string strAlphabet;
    for (const char& character : u_setAlphabet)
        strAlphabet += character;
    return strAlphabet;
}

Is this a good way to solve this task? The additions of signle chars to string seems not to be optimal for large u_setAlphabet (multiple reallocs?). Is there any other method to it?

Upvotes: 6

Views: 1368

Answers (4)

hungptit
hungptit

Reputation: 1444

Both return std::string(u_setAlphabet.begin(), u_setAlphabet.end()); and return { u_setAlphabet.begin(), u_setAlphabet.end(); are the same in C++11. I prefer @VladfromMoscow solution because we do not need to make any assumption about the returned type of the temporary object.

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 477650

The simplest, most readable and most efficient answer is:

return std:string(s.begin(), s.end());

The implementation may choose to detect the length of the range up-front and only allocate once; both libc++ and libstdc++ do this when given a forward iterator range.

The string class also offers you reserve, just like vector, to manage the capacity:

std::string result
result.reserve(s.size());
for (unsigned char c : s) result.push_back(c);   // or std::copy
return result;

It also offers assign, append and insert member functions, but since those offer the strong exception guarantee, they may have to allocate a new buffer before destroying the old one (thanks to @T.C. for pointing out this crucial detail!). The libc++ implementation does not reallocate if the existing capacity suffices, while GCC5's libstdc++ implementation reallocates unconditionally.

Upvotes: 12

Vlad from Moscow
Vlad from Moscow

Reputation: 311146

It is better to use the constructor that acepts iterators. For example

std::string getAlphabet() {
    return { u_setAlphabet.begin(), u_setAlphabet.end() };
}

Upvotes: 10

xtofl
xtofl

Reputation: 41519

std::string has a constructor for that:

auto s = std::string(begin(u_setAlphabet), end(u_setAlphabet));

Upvotes: 12

Related Questions