Click to See Complete Forum and Search --> : STL string gurus - please help!


Mike Pliam
June 7th, 2008, 07:30 PM
I wish to replace a set of substrings in a string. I have experimented with various methods to do this. I thought I had it working, but no... under certain circumstances that I do not understand but can readily reproduce, my code encounters a runtime error with the message: 'the string iterator is not dereferencable'.

Here's the code I have been trying to develop:

int count;
char buf[256];
double x[7];
string s, so, sr;
string::iterator tt;
vector<string> vs1, vs2;

x[0] = 1.123234345;
x[1] = 2.293849223;
x[2] = 3.283746834;
x[3] = 4.758439842;
x[4] = 5.234543234;
x[5] = 6.728394823;
x[6] = 7.923874943;

s = "t = %0.8f\nu = %0.8f\nv = %0.8f\nw = %0.8f\nx = %0.8f\ny = %0.8f\nz = %0.8f\n";
cout << s << endl;


so = "%0.8f";
tt = s.begin();
count = 0;
while(tt != s.end())
{
if(*tt == '%')
{
sprintf(buf, "%0.4f", x[count]);
//sprintf(buf, "%0.5f", x[count]); // error: string iterator not dereferencable
sr = string(buf);
s.replace(tt, tt + so.size(), sr);
count++;
}
*tt++;
}

cout << s << endl;



Now, at first glance, I thought I understood the problem, that is, I thought that the replacement string cannot be longer than the substring one wishes to replace. Thus, so = "%0.8f"; has 5 characters (plus '\0'), so that using a 6 or greater length string will cause the replace function iterator to fail.

But further experimentation shows that this is probably NOT the problem. For example, this code works without a problam

size_t n;
string s, so, sr;
string::iterator tt;

s = "x = %0.8f";
so = "%0.8f";
sr = "123233453454.345445645645656567";

cout << s << endl;

n = s.find('%', 0);
tt = s.begin() + n;

s.replace(tt, tt + so.size(), sr);

cout << s << endl;

// output: x = 123233453454.345445645645656567



Frankly, I am at a loss to know what's happening here. Any of your ideas would certainly be appreciated. Thanks.

Mike

ovidiucucu
June 7th, 2008, 11:58 PM
[ Moved thread ]

spoon!
June 8th, 2008, 01:41 AM
the iterator "tt" is invalidated by replace()

Duoas
June 8th, 2008, 10:34 AM
I think you are going about it the hard way, plus you are using C functions like scanf(), which don't help.

Here's how to do it with standard streams and iterators.
Method One is just building the string (no replacing involved).
Method Two is essentially a string replace in that it only copies the stuff it wants out of the source string...

#include <algorithm> // copy()
#include <iomanip> // setprecision()
#include <iostream>
#include <iterator> // back_insert_iterator<>
#include <sstream>
#include <string>
using namespace std;

//----------------------------------------------------------
string method_one( double x[7] )
//
// Build the result string from scratch
{
char names[] = "tuvwxyz";
stringstream result;

for (int i = 0; i < 7; i++)
result << names[i] << " = " << fixed << setprecision( 4 ) << x[i] << endl;

return result.str();
}

//----------------------------------------------------------
string method_two( const string& s, const string& subs, double x[] )
//
// Build the result string by replacing stuff in 's'
{
string result;
string::const_iterator nexti, i = s.begin();
back_insert_iterator <string> ri( result );

for (int n = 0; true; n++)
{
// Find the next matching substring
nexti = search( i, s.end(), subs.begin(), subs.end() );
if (nexti == s.end()) break;

// Copy everything before the matching part
copy( i, nexti, ri );

// Convert x to string and add it instead of the matching part of s
stringstream ss;
ss << fixed << setprecision( 4 ) << x[n];
string t = ss.str();
copy( t.begin(), t.end(), ri );

i = nexti +subs.length();
}
// Copy any remaining part
copy( i, s.end(), ri );

return result;
}

//----------------------------------------------------------
int main()
{
double x[7] = {
1.123234345,
2.293849223,
3.283746834,
4.758439842,
5.234543234,
6.728394823,
7.923874943
};

cout << "method one: \"" << method_one( x ) << "\"\n";

cout << "method two: \"" << method_two(
"t = %0.8f\nu = %0.8f\nv = %0.8f\nw = %0.8f\nx = %0.8f\ny = %0.8f\nz = %0.8f\n",
"%0.8f",
x
) << "\"\n";

return 0;
}


Doing an actual replace is not that hard either, but that's where you'll hit the limitations of the STL's iterator capabilities... (hopefully C++0x fill fix some of those flaws).

Hope this helps.

Mike Pliam
June 8th, 2008, 11:38 AM
Thank you so very much for your kind help.

Do you think that the problem I have encountered with 'release' represents a coding error on my part or a bug in the STL ?

Mike :)

souldog
June 8th, 2008, 11:54 AM
coding error on your part

Duoas
June 8th, 2008, 02:21 PM
Yes, it is exactly as spoon! said: all iterators into a container are invalidated whenever you use insert() or replace(), etc.

The probability of new programmers and even very experienced folk such as myself finding a bug in the STL is close enough to zero that we might as well consider it as "can't happen." Leave that kind of stuff to the STL committee experts.

Hope this helps.

souldog
June 8th, 2008, 02:54 PM
all iterators into a container are invalidated whenever you use insert() or replace(), etc.


That depends on the container.

Mike Pliam
June 10th, 2008, 08:30 PM
According to Herb Schildt (C++, The Complete Reference), strstream is deprecated, even though it is still supported by most compilers because it is so widely used. Visual Studio gives no indication that strstream is deprecated. Is it OK to continue to use it, or is there some more uptodate alternative ?

Mike

souldog
June 10th, 2008, 08:50 PM
http://www.cplusplus.com/reference/iostream/stringstream/

Mike Pliam
June 11th, 2008, 02:18 PM
Good reference. stringstream is still OK. Schildt was referring to strstream. I need to read things more carefully. Thanks. :o