当使用std::cout
向控制台输出内容时,我注意到了一种相当奇怪的行为
我编写了两个函数string& toUpper(std::string &str)
和string& toLower(std::string &str)
,它们应该完全按照它们的名称进行操作:将字符串全部转换为大写或全部小写。
#include <string>
using namespace std;
string& toLower(string &str)
{
for(char &c : str)
c = tolower(c);
return str;
}
string& toUpper(string &str)
{
for(auto &c : str)
c = toupper(c);
return str;
}
现在我独立测试了这两个功能,它们按预期工作。然后我在cout
电话中链接了他们两个:
string str = "Hello World";
cout << toLower(str) << endl << toUpper(str) << endl;
我预计输出为
hello world
HELLO WORLD
但我只是得到了
hello world
hello world
我使用printf
进行了同样的测试,因为我认为这可能是cout
做某事的方式所特有但我得到了相同的结果,所以我猜我的代码出了问题。
我的代码有什么问题?
答案 0 :(得分:4)
您正在修改表达式求值中的变量(字符串),并且依赖于在评估期间的某些点使用它。正如您所发现的那样,您无法依赖它。
一种解决方案是使用不同的字符串;另一个是打破表达:
cout << toLower(str) << endl;
cout << toUpper(str) << endl;
答案 1 :(得分:4)
它是c ++解析你的陈述的方式:
cout << toLower(str) << endl << toUpper(str) << endl; //str = Hello World
第一步评估到上一个:
cout << toLower(str) << endl << str << endl;//str = HELLO WORLD
第二步评估为下:
cout << str << endl << str << endl;//str = hello world
第3步评估cout:
cout <<"hello world\nhello world\n";
你的cout产生这个结果的原因是因为它在打印之前修改了相同的字符串。使用副本而不是引用来解决此问题。
答案 2 :(得分:4)
对operator<<
的调用必须按顺序从左到右进行,但C ++标准没有指定语句中子表达式的评估顺序。
编译器可以决定评估子表达式的顺序,以便任何这些结果都有效:
auto&& arg1 = toLower(str);
auto&& arg2 = toUpper(str);
cout << arg1 << endl << arg2 << endl;
或者:
auto&& arg1 = toUpper(str);
auto&& arg2 = toLower(str);
cout << arg2 << endl << arg1 << endl;
或者:
auto&& arg1 = toUpper(str);
auto&& arg2 = (cout << arg1);
auto&& arg3 = toUpper(str);
arg2 << endl << arg3 << endl;
或其他几种可能性。在这三种可能的顺序中,只有最后一种顺序会产生您期望的结果。第一个案例将导致&#34; HELLO WORLD&#34;打印两次,第二种情况是编译器得到的结果。根据C ++标准,所有这些都是有效的结果。
答案 3 :(得分:0)
问题是&#34;当它调用函数&#34;以及如何处理引用。由于它是一个缓冲流,它似乎可能无序地调用它们。如果删除返回的字符串的引用(因此,您为每个函数返回一个新的唯一字符串),代码将正常工作。
void toLower(string &str)
{
for(char &c : str)
c = tolower(c);
return str;
}
void toUpper(string &str)
{
for(auto &c : str)
c = toupper(c);
}