Hi Please tell me why std::string::at() can changed its status in below test function(resolved)

Sorry Im wrong!!!
forget about it!!!
Thanks Pharap!!!

I’m not sure quite what you’re asking, or what’s surprising about the output.

As far as I can see the code does exactly what’s expected:

  • revereStr reverses the std::string given as an argument,
    and returns that argument (i.e. the same object reference)
  • foolreverseStr doesn’t even attempt to reverse the string,
    it merely removes the last character in the string in a very inefficient way
    • Specifically it constructs a second string by appending characters from the first string up until one character before the end, and then swaps the two strings

Perhaps you are confused by the fact the argument is modified?
In which case you may have misunderstood how std::string::swap works,
or that the argument is passed as a non-const reference,
which means it’s not a copy, it’s the original string, and can be modified.

What behaviour were you expecting?


foolreverseStr could be better expressed as:

std::string & dropLast(std::string & string)
{
	const std::size_t index = (string.size() - 1);
	string.erase(index, 1);
	return string;
}

Or if you prefer one-liners:

std::string & dropLast(std::string & string)
{
	return string.erase(string.size() - 1, 1);
}

While I’m at it, there’s a more efficient way to reverse a std::string.
Simply #include <algorithm> and then std::reverse(string.begin(), string.end());,
which will reverse the string in place, no need to allocate a new string.

The <algorithm> library is your friend, use it well.

1 Like

I tested a little code that letting the string reversed.
Two functions that doing the same thing(std::string& reverseStr(std::string& str) and std::string& foolreverseStr(std::string& str))
But I didnt notice the reference parament in two functions and referenced the same object twice, so I answer the stupid question.
Wasted your time!!! Im foolish.

#include <iostream>
#include <string>

std::string& reverseStr(std::string& str){
    std::string tmp(str.rbegin(),str.rend());
    str.swap(tmp);
    return str;
}

std::string& foolreverseStr(std::string& str){
    std::string tmp;
    char tmp2[1];
    for(size_t i = str.size() - 1; i >= 0 && i < str.size()  ; i--){
        tmp2[0] = str.at(i);
        tmp.append(tmp2, 1);
    }
    str.swap(tmp);
    return str;
}

int main(){
    std::string str("hello world!");
    std::cout << foolreverseStr(str) << '\n'; 
    std::cout << reverseStr(str) << '\n';
    std::cout << foolreverseStr(str) << '\n'; 
    return 0;
}

If you want to create a new string instead of modifying the existing string, you’d need something like this:

// Return value optimisation guarantees that the created string will be moved instead of copied
std::string createReversedString(const std::string & string)
{
	return std::string(string.rbegin(), string.rend());
}

Two tips:

You should have a std:: in front of std::size_t.

For most compilers it doesn’t make a difference, but technically C++ is not guaranteed to defined size_t in the global namespace, so your code could break on some compilers.

See cppreference for more info. (Also available in Chinese.)

A better way to decrement std::size_t without invoking underflow is to keep the loop variable 1 larger than the value you want to use:

for(std::size_t index = string.size(); index > 0; --index)
{
	const char c = string.at(index - 1);
	result.append(&c, 1);
}
1 Like

const char c = string.at(index - 1);
smart!!!

1 Like