32

I have 2 std::string. I just want to, given the input string:

  1. capitalize every letter
  2. assign the capitalized letter to the output string.

How come this works:

  std::string s="hello";
  std::string out;
  std::transform(s.begin(), s.end(), std::back_inserter(out), std::toupper);

but this doesn't (results in a program crash)?

  std::string s="hello";
  std::string out;
  std::transform(s.begin(), s.end(), out.begin(), std::toupper);

because this works (at least on the same string:

  std::string s="hello";
  std::string out;
  std::transform(s.begin(), s.end(), s.begin(), std::toupper);
sivabudh
  • 30,701
  • 59
  • 159
  • 223
  • 5
    None of this examples compiles correctly in my case (gcc 4.7), i guess because `std::toupper` has been overloaded with a two arguments variant (provided by `locale.h`). I had to cast it explicitly: `std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))std::toupper);` – Gab Apr 08 '14 at 09:21

3 Answers3

48

There is no space in out. C++ algorithms do not grow their target containers automatically. You must either make the space yourself, or use a inserter adaptor.

To make space in out, do this:

out.resize(s.length());

[edit] Another option is to create the output string with correct size with this constructor.

std::string out(s.length(), 'X');

hrnt
  • 9,622
  • 2
  • 29
  • 38
  • What's the difference between this and (Both are strings): std::string s2(s1); std::transform(s2.begin(), s2.end(), s2.begin(), std::toupper); ? Oh, I just answered my own question I think, in the first case it's just resizing the string. But in the second case I think it's equivalent? – Aaron H. Feb 11 '15 at 21:53
  • 1
    See the following: http://stackoverflow.com/questions/7131858/stdtransform-and-toupper-no-matching-function http://www.cplusplus.com/reference/iterator/back_inserter/ (though I will probably use resize myself for speed purposes) – Andrew Jul 17 '15 at 05:15
2

I'd say that the iterator returned by out.begin() is not valid after a couple of increments for the empty string. After the first ++ it's ==out.end(), then the behavior after the next increment is undefined.

After all this exactly what insert iterator is for.

Michael Krelin - hacker
  • 131,515
  • 23
  • 189
  • 171
  • 1
    Wouldn't .begin() equal .end() immediately for an empty string, rather than after the first increment? – Kylotan Sep 29 '09 at 13:44
0

Thats the sense of a backinserter: It inserts elements to a container. using begin(), you pass a iterator to a empty container and modify invalid iterators.

I am sorry - my edits interfered with your comments. I first posted something wrong accidentally.

RED SOFT ADAIR
  • 11,639
  • 10
  • 50
  • 86