0

Here is a C++ snippet which inserts a dot . before every character in the string.

Here's my code:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string s;
    cin >> s;

    for (auto it = s.begin(); it != s.end(); it++)
    {
          s.insert(it, '.');
          it++;
    }

    cout << s;
}

Here I am using iterators and after inserting . before a character. I am incrementing iterator because the insert method sets the iterator to the position where the new character is inserted.

But something weird is happening, I am getting runtime error for some inputs:

For example:

Input: abcde
Output: .a.b.c.d.e

Input: abcdef
Output: .a.b.c.d.e.f

Input: abcdefg
Output: .a.b.c.d.e.f.g

Input: abcdefgh
Output: Getting runtime error 

~~Dr.M~~ Error #1: UNADDRESSABLE ACCESS beyond heap bounds: reading 0x10fb4fa7-0x10fb4fa8 1 byte(s)
~~Dr.M~~ # 0 replace_memmove                                            [d:\drmemory_package\drmemory\replace.c:802]
~~Dr.M~~ # 1 std::char_traits<>::move                                   [C:/Programs/mingw-w64-7/lib/gcc/i686-w64-mingw32/7.3.0/include/c++/bits/char_traits.h:342]
~~Dr.M~~ # 2 std::__cxx11::basic_string<>::_S_move                      [C:/Programs/mingw-w64-7/lib/gcc/i686-w64-mingw32/7.3.0/include/c++/bits/basic_string.h:349]
~~Dr.M~~ # 3 std::__cxx11::basic_string<>::_M_replace_aux               [C:/Programs/mingw-w64-7/lib/gcc/i686-w64-mingw32/7.3.0/include/c++/bits/basic_string.tcc:407]
~~Dr.M~~ # 4 std::__cxx11::basic_string<>::insert      

I am not able to understand why this is happening, please help me in this.

Note: I know there are other ways of solving this problem but I am curious to know what is happening here.

Azeem
  • 11,148
  • 4
  • 27
  • 40
Rishab Shinghal
  • 591
  • 3
  • 16
  • 3
    Modifying a container that you're iterating over is a good recipe for disaster. I suggest you take a closer look at the different [`insert` overloads](https://en.cppreference.com/w/cpp/string/basic_string/insert) to find something appropriate which return a suitable iterator. – Some programmer dude Apr 01 '20 at 08:55
  • 2
    You are breaking the rule. Iterator is invalidated when the container has modified. https://stackoverflow.com/questions/6438086/iterator-invalidation-rules – MyBug18 Apr 01 '20 at 08:56
  • Why don't you just create a new string, instead of doing all of the gymnastics of calling `insert`? You could just easily loop, and concatenate the letter and dot onto a new string. – PaulMcKenzie Apr 01 '20 at 09:05
  • `std::string newString = std::accumulate(s.begin(), s.end(), std::string(),[](std::string& t, char c) { return t + "." + c; }); s = newString;` – PaulMcKenzie Apr 01 '20 at 09:15

1 Answers1

2

the insert method sets the iterator to the position where the new character is inserted.

No it doesn't, it returns an iterator to the inserted character. Try this

it = s.insert(it, '.');
it++;

or simpler

it = s.insert(it, '.') + 1;
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
john
  • 85,011
  • 4
  • 57
  • 81
  • in my example, suppose iterator points to character 'r', after inserting '.' before 'r', iterator points to '.' You can verify by dereferencing it ( *it) – Rishab Shinghal Apr 01 '20 at 09:03
  • 1
    No, affter inserting the iterator is **invalidated**. You cannot use it without getting undefined behaviour (which is exactly what you are seeing). That is why you must use the return value from `insert` instead. .But you don't have to believe me if you don't want to. – john Apr 01 '20 at 09:05
  • ok, yeah you are right, I also wanted to know after erasing the character also iterator is invalidated? – Rishab Shinghal Apr 01 '20 at 09:07
  • Yes, erasing on a string also invalids iterators. But again some of the erase methods return a new valid iterator. – john Apr 01 '20 at 09:08