string insert breaks iterator

This is a discussion on string insert breaks iterator within the C++ Programming forums, part of the General Programming Boards category; I'm attempting to escape chars in a wstring by iterating over the string and inserting an escape character in the ...

  1. #1
    Registered User
    Join Date
    Dec 2008
    Posts
    2

    string insert breaks iterator

    I'm attempting to escape chars in a wstring by iterating over the string and inserting an escape character in the appropriate location. The function below is preparing INSERT statements for SQL by adding a single quote to existing single quotes in the string. ( e.g. ( ' ) becomes ( '' ) ). The odd thing is that all string insertions work as expected except on a single case where the error is given. The string that's giving the error isn't special in any way. There's a single quote in the middle of the string and string insert updates it as expected. But, after the insert the iterator is broken and on the subsequent dereferences the error is given.


    Debug Assertion Failed!
    Expression: string iterator not dereferencable.


    Code:
            wstring str( "Some string with a ' single quote in it." )
            wstring::iterator iter;
    	for( iter = str.begin(); iter != str.end(); ++iter )
    	{
    		if( *iter == L'\'' )
    		{	
    			str.insert( iter++, L'\'' );			
    		}
    	}

    Any help is very much appreciated.

    Andrew

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    It is fairly normal for iterators to be invalidated by modification of the string itself. If you consider that a string is basically a pointer to a chunk of memory, and the iterator is a pointer to some element in that memory. If you insert something, the string may well be moved to another chunk of memory - so now your pointer is no longer pointing to the same bit of memory as before.

    I'd suggest you have two strings: the original and the modified one. When copy everything one character at a time, and modify the quotes by adding it twice to the new string. It's not the fastest method, but it will solve the problem, and unless you actually find that it's too slow, it should be fine.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    20,973
    The problem is that insertion might invalidate iterators. However, you should be able to do something like this:
    Code:
    wstring str( "Some string with a ' single quote in it." )
    wstring::iterator iter;
    for( iter = str.begin(); iter != str.end(); ++iter )
    {
        if( *iter == L'\'' )
        {
            iter = str.insert( iter, L'\'' );
        }
    }
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,159
    Quote Originally Posted by matsp View Post
    I'd suggest you have two strings: the original and the modified one. When copy everything one character at a time, and modify the quotes by adding it twice to the new string. It's not the fastest method, but it will solve the problem, and unless you actually find that it's too slow, it should be fine.
    Actually, it probably would be faster than inserting in the string itself, since each insertion involves moving the whole rest of the string over by one character.

    As far as invalidating iterators, if you use indices instead of iterators your code won't break when the string gets reallocated.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  5. #5
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Katy, Texas
    Posts
    2,309
    Iterators in C++ are touchy when you modify the container they operate on. If you are changing the size of the container, (in this case, your string), your iterators are subject to immediately becoming invalidated.
    Mac and Windows cross platform programmer. Ruby lover.

    Quote of the Day
    12/20: Mario F.:I never was, am not, and never will be, one to shut up in the face of something I think is fundamentally wrong.

    Amen brother!

  6. #6
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Katy, Texas
    Posts
    2,309
    Wow - that's a lot of immediate answers!!
    Mac and Windows cross platform programmer. Ruby lover.

    Quote of the Day
    12/20: Mario F.:I never was, am not, and never will be, one to shut up in the face of something I think is fundamentally wrong.

    Amen brother!

  7. #7
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,159
    Quote Originally Posted by Dino View Post
    Iterators in C++ are touchy when you modify the container they operate on. If you are changing the size of the container, (in this case, your string), your iterators are subject to immediately becoming invalidated.
    Depends on the container. A std::map's iterators remain valid after an insertion.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by brewbuck View Post
    Actually, it probably would be faster than inserting in the string itself, since each insertion involves moving the whole rest of the string over by one character.

    As far as invalidating iterators, if you use indices instead of iterators your code won't break when the string gets reallocated.
    Aside from better suggestions by Daved and Laserlight, sure, it's certainly faster - but unless this is really a performance hotspot, I'd say it's unimportant to do that.

    Using indices is not the C++ way - it makes it look like standard C, doesn't it? [Being more of a C and C++ programmer, I quite like this idea - but I can see others at my work shooting it down pretty darn quickly].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    Dec 2008
    Posts
    2
    Wow... I've never posted to a forum and gotten such an array of quality responses. Thank you to all of you for your expertise. I went from a dead-end to multiple roads in minutes.

    I ended up doing this:

    Code:
    iter = str.insert( iter, L'\'' );	// basic_string<wstring>::insert() returns an iterator with the new position.
    iter++;

    Thanks again.
    Andrew

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Andrew, this forum is great if you have a SPECIFIC question about something concrete. Which is what you did - well done.

    Ask woolly questions, and expect sarcastic/idiotic/funny/useless comments.

    Ask for your homework to be done, and you get no real help until posting some code.

    And of course, "You get what you ask for", so if you ask "Can I open a JPEG image", then the answer is undoubtedly "Yes, it can be done".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by AndrewL View Post
    Wow... I've never posted to a forum and gotten such an array of quality responses. Thank you to all of you for your expertise. I went from a dead-end to multiple roads in minutes.

    I ended up doing this:

    Code:
    iter = str.insert( iter, L'\'' );	// basic_string<wstring>::insert() returns an iterator with the new position.
    iter++;

    Thanks again.
    Andrew
    That's precisely one of the examples in Chapter 84. Prefer algorithm calls to handwritten loops
    I could be wrong, but I think you could use something like std::inserter( str, iter ); for that.
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    20,973
    Quote Originally Posted by AndrewL
    I ended up doing this:
    Are you sure that increment is correct? You increment the iterator in the for loop, after all.

    Quote Originally Posted by cpjust
    That's precisely one of the examples in Chapter 84. Prefer algorithm calls to handwritten loops
    I could be wrong, but I think you could use something like std::inserter( str, iter ); for that.
    std::inserter is an iterator adapter, not an algorithm, so on its own it cannot replace the loop.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by laserlight View Post
    Are you sure that increment is correct? You increment the iterator in the for loop, after all.
    I believe it is correct - it skips over the just inserted extra quote character - otherwise you'd end up with an infinite loop that inserst an infinite number of single quotes.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  14. #14
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    20,973
    Quote Originally Posted by matsp
    I believe it is correct - it skips over the just inserted extra quote character - otherwise you'd end up with an infinite loop that inserst an infinite number of single quotes.
    Oh yes, because the insertion happens before point that the iterator points to.

    In that case I would point out that prefix increment is preferred.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #15
    The larch
    Join Date
    May 2006
    Posts
    3,573
    If you want to avoid coding the loop manually:

    Code:
    #include <string>
    #include <boost/algorithm/string/replace.hpp>
    
    int main()
    {
        std::wstring s(L"Some string with a ' single quote in it.");
        boost::replace_all(s, L"'", L"''");
    }
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. OOP Question DB Access Wrapper Classes
    By digioz in forum C# Programming
    Replies: 2
    Last Post: 09-07-2008, 04:30 PM
  2. Program using classes - keeps crashing
    By webren in forum C++ Programming
    Replies: 4
    Last Post: 09-16-2005, 03:58 PM
  3. Link list library
    By Brighteyes in forum C Programming
    Replies: 4
    Last Post: 05-12-2003, 08:49 PM
  4. creating class, and linking files
    By JCK in forum C++ Programming
    Replies: 12
    Last Post: 12-08-2002, 01:45 PM
  5. Again Character Count, Word Count and String Search
    By client in forum C Programming
    Replies: 2
    Last Post: 05-09-2002, 11:40 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21