Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are
spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the
password reset link.
Entire forum
➜ Programming
➜ General
➜ std::string::erase
It is now over 60 days since the last post. This thread is closed.
Refresh page
Posted by
| Terry
USA (87 posts) Bio
|
Date
| Wed 02 Dec 2009 04:43 PM (UTC) Amended on Wed 02 Dec 2009 04:45 PM (UTC) by Terry
|
Message
| On a more serious note than my last post... :P I'm trying to delete leading spaces using .erase() . However, I'm getting some weird bug that I can't understand. Maybe you guys can shed some light on the matter. :)
darkness@linux:~$ cat eval.cpp
#include <cstdlib>
#include <iostream>
#include <string>
int main()
{
const std::string str = " foo ";
size_t spaces;
for(spaces = 0; str[spaces] == ' '; ++spaces);
str.erase(0, spaces - 1);
std::cout << "Number of leading spaces: " << spaces << std::endl;
std::cout << "New string: \"" << str << "\"" << std::endl;
return EXIT_SUCCESS;
}
darkness@linux:~$ g++ -o eval eval.cpp
eval.cpp: In function âint main()â:
eval.cpp:13: error: passing âconst std::stringâ as âthisâ argument of âstd::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::erase(typename _Alloc::rebind<_CharT>::other::size_type, typename _Alloc::rebind<_CharT>::other::size_type) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]â discards qualifiers
Obviously, I was expecting the output to be:
Number of leading spaces: 4
New string: "foo "
| Top |
|
Posted by
| Nick Cash
USA (626 posts) Bio
|
Date
| Reply #1 on Wed 02 Dec 2009 04:49 PM (UTC) Amended on Wed 02 Dec 2009 04:52 PM (UTC) by Nick Cash
|
Message
|
const std::string str = " foo ";
The erase method modifies the string, so C++ is protecting you since you declared it as const. Try removing const.
Also,
str.erase(0, spaces - 1);
You don't need to subtract one. I'm sure you would find that in your testing, but for completeness my OCD demands I point it out. :) |
~Nick Cash
http://www.nick-cash.com | Top |
|
Posted by
| Terry
USA (87 posts) Bio
|
Date
| Reply #2 on Wed 02 Dec 2009 04:51 PM (UTC) |
Message
| *facepalm* CRAIIIIII *sigh* i r idjit... :P thanks though... | Top |
|
Posted by
| Nick Cash
USA (626 posts) Bio
|
Date
| Reply #3 on Wed 02 Dec 2009 04:54 PM (UTC) |
Message
| Programmers make errors; it is a fact of life. No reason to beat yourself up! I've certainly made sillier mistakes. Sometimes you just need another pair of eyes to point out the obvious things you are missing :) |
~Nick Cash
http://www.nick-cash.com | Top |
|
Posted by
| David Haley
USA (3,881 posts) Bio
|
Date
| Reply #4 on Wed 02 Dec 2009 05:26 PM (UTC) |
Message
| One thing to keep in mind is that you said this:
Quote: Obviously, I was expecting the output to be:
but, your program hadn't compiled yet. The error message is admittedly rather cryptic, but any message of the form:
error: passing const XXX as argument to YYY discards qualifies
means that you are passing a const object to something that expects a non-const object. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | Top |
|
Posted by
| Wjmurdick
(13 posts) Bio
|
Date
| Reply #5 on Thu 03 Dec 2009 02:50 PM (UTC) Amended on Fri 04 Dec 2009 09:43 PM (UTC) by Nick Gammon
|
Message
| I wrote a trim function for a project a while back that used std::string. You could always use it if you wish. I've also got a char* version.
void str_ltrim (string& str)
{
string mstr;
int i=0, j, len;
if (str.empty()) return;
mstr = str;
while (mstr[i] == ' ') {
j = i;
i++;
};
if (j == 0) return;
len = mstr.length() - j;
str = mstr.substr(j+1, len);
}
void str_rtrim (string& str)
{
string mstr;
int i=0, j, len;
if (str.empty()) return;
mstr = str;
len = mstr.length();
i = len-1;
while (mstr[i] == ' ') {
j = i;
i--;
};
if (j == len) return;
str = mstr.substr(0, j);
}
| Top |
|
Posted by
| Samson
USA (683 posts) Bio
|
Date
| Reply #6 on Fri 04 Dec 2009 01:21 AM (UTC) Amended on Fri 04 Dec 2009 09:43 PM (UTC) by Nick Gammon
|
Message
| I've been using these for awhile now and they work perfectly.
void strip_lspace( string & line )
{
string::size_type space;
space = line.find_first_not_of( ' ' );
if( space == string::npos )
space = 0;
line = line.substr( space, line.length( ) );
space = line.find_first_not_of( '\t' );
if( space == string::npos )
space = 0;
line = line.substr( space, line.length( ) );
}
void strip_tspace( string & line )
{
string::size_type space;
space = line.find_last_not_of( ' ' );
if( space != string::npos )
line = line.substr( 0, space + 1 );
}
void strip_spaces( string & line )
{
strip_lspace( line );
strip_tspace( line );
}
| Top |
|
Posted by
| David Haley
USA (3,881 posts) Bio
|
Date
| Reply #7 on Fri 04 Dec 2009 01:36 AM (UTC) |
Message
| Two suggestions:
- first_first_not_of allows you to specify several characters at once, so you can scan for spaces and tabs at the same time. This is (in almost all cases) more efficient than scanning the string twice.
- I would make const versions that return a string, so that you can easily apply the functions to const strings. As a convenience to maintain interface, you might consider having the non-const version return a reference to the argument as well.
Note that strip_lspace trims spaces and tabs, but strip_tspace only removes spaces.
Finally, if efficiency matters (and it probably doesn't) the two strip phases can be combined into a single phase, so that you only have one substring operation. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | Top |
|
Posted by
| Nick Gammon
Australia (23,120 posts) Bio
Forum Administrator |
Date
| Reply #8 on Fri 04 Dec 2009 09:46 PM (UTC) Amended on Fri 04 Dec 2009 09:47 PM (UTC) by Nick Gammon
|
Message
| Here is my version:
#define SPACES " \t\r\n"
inline string trim_right (const string & s, const string & t = SPACES)
{
string d (s);
string::size_type i (d.find_last_not_of (t));
if (i == string::npos)
return "";
else
return d.erase (d.find_last_not_of (t) + 1) ;
} // end of trim_right
inline string trim_left (const string & s, const string & t = SPACES)
{
string d (s);
return d.erase (0, s.find_first_not_of (t)) ;
} // end of trim_left
inline string trim (const string & s, const string & t = SPACES)
{
string d (s);
return trim_left (trim_right (d, t), t) ;
} // end of trim
This trims whitespace (which you can define exactly what it is) from the left, right, or both sides of a string. This is used in MUSHclient.
The trimmed string is returned, the source string is unchanged. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| David Haley
USA (3,881 posts) Bio
|
Date
| Reply #9 on Sat 05 Dec 2009 03:36 AM (UTC) |
Message
| Those could probably be made ever so slightly more efficient by using a substr on the const std::string argument, instead of copying into a modifiable string first. The 'erase' and 'substr' both require what is basically a string copy, but you can avoid the extra copy into a modifiable string. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | Top |
|
Posted by
| Nick Cash
USA (626 posts) Bio
|
Date
| Reply #10 on Sat 05 Dec 2009 05:45 AM (UTC) |
Message
| It would seem David is a performance nazi :P
I would post some of the C-string functions I wrote to win one of the MudMagic coding competitions, but I think we would all be horrified! |
~Nick Cash
http://www.nick-cash.com | Top |
|
Posted by
| David Haley
USA (3,881 posts) Bio
|
Date
| Reply #11 on Sat 05 Dec 2009 07:46 AM (UTC) |
Message
| Heh, sorry, some habits die hard. :-) When I see "library functions" my brain goes into code-review mode and my instinct is to improve them where easily possible. I won't go to the extremes of squeezing out every last assembly cycle, but when improvements are easy I think it can't hurt to mention them.
If you will indulge an apparent self-contradiction, I will note that improving performance isn't always a worthwhile endeavor; it is only important that things be "fast enough", not "as fast as possible". If you're going to spend time on improving performance -- as opposed to making small, easy changes -- you should make sure that you're gaining real benefit for your time invested. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | Top |
|
Posted by
| Nick Gammon
Australia (23,120 posts) Bio
Forum Administrator |
Date
| Reply #12 on Sat 05 Dec 2009 09:56 AM (UTC) |
Message
| It might also be more efficient to do a test first to see if the (probably frequent) case of no spaces is there, to save more work. For example, if there is no space in the first position, when trimming leading spaces, simply return the source string. However this would only be more efficient if the source string usually did not have spaces. If it always did, then that would be slower.
However there is also something to be said for the function to be readable, and, as you say, if it is fast enough, then that may be very adequate.
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Nick Cash
USA (626 posts) Bio
|
Date
| Reply #13 on Sun 06 Dec 2009 12:03 AM (UTC) Amended on Sun 06 Dec 2009 12:04 AM (UTC) by Nick Cash
|
Message
|
Quote:
Heh, sorry, some habits die hard.
No worries. Critical reviewing of code is not a habit you should be killing. I am a performance nazi as well, but it is generally required for embedded systems!
Quote:
... you should make sure that you're gaining real benefit for your time invested.
This is something that is very hard to get across to the interns that I work with. Most of them see no benefit in refactoring/optimization, and others take it too far! It is an important lesson to learn though, as your time is precious :) |
~Nick Cash
http://www.nick-cash.com | Top |
|
Posted by
| Samson
USA (683 posts) Bio
|
Date
| Reply #14 on Sun 06 Dec 2009 11:07 AM (UTC) |
Message
|
David Haley said: *first_first_not_of allows you to specify several characters at once, so you can scan for spaces and tabs at the same time. This is (in almost all cases) more efficient than scanning the string twice.
I wasn't aware of that. Good to know.
Also not terribly worried about using it on const strings.
Quote: Note that strip_lspace trims spaces and tabs, but strip_tspace only removes spaces.
That's probably only because the use case for the functions even existing never had a situation where tabs would show up after the string, but they sometimes did before. I used them for cleaning up file input after converting most of them to read using the filestream libraries.
Quote: Finally, if efficiency matters (and it probably doesn't) the two strip phases can be combined into a single phase, so that you only have one substring operation.
Not sure there's a point in combining. Most of the usage only calls on strip_lspace. strip_tspace came later, and strip_spaces was just a convenient way to do both in situations that needed it. I supposed if they were going to get used for general purpose functions then combining them into a single one would be more sensible. | Top |
|
The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).
To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.
41,774 views.
It is now over 60 days since the last post. This thread is closed.
Refresh page
top