::tolower using std::transform

362 Views Asked by At

Why std::transform doesn't work this way:

std::string tmp = "WELCOME";
std::string out = "";
std::transform(tmp.begin(), tmp.end(), out.begin(), ::tolower);

out is empty!

But this works:

std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);

I don't want the transformation to happen in-place.

2

There are 2 best solutions below

4
On BEST ANSWER

You are writing in out-of-bounds memory, since the range of out is smaller than that of tmp. You can store the result in out by applying std::back_inserter.

As user17732522 pointed out, since it's not legal to take the adress of a standard libary function, it's better to pass over a lamda object that calls std::tolower on the character when needed.

std::transform(tmp.begin(), tmp.end(), std::back_inserter(out), [](auto c) {
    return std::tolower(static_cast<unsigned char>(c));
});
1
On

One way is to resize the string to allocate sufficient memory for std::transform to populate it.

out.resize(tmp.size()); // <---
std::transform(tmp.begin(), tmp.end(), out.begin(), ::tolower);

Alternatively, as others have mentioned you could use std::back_inserter, which handles inserting for you. We can also call out.reserve to save time on allocations (especially if your string is large).

out.reserve(tmp.size()); // (optional) Smol optimisation.
std::transform(tmp.begin(), tmp.end(), std::back_inserter(out), ::tolower);