C++ 怪异的行为

C++ 怪异的行为,c++,string,C++,String,在使用std::cout向控制台输出内容时,我注意到一种非常奇怪的行为。 我编写了两个函数string&toUpper(std::string&str)和string&toLower(std::string&str),它们应该完全按照后面的调用来执行:将字符串转换为全大写或全小写 #include <string> using namespace std; string& toLower(string &str) { for(char &c : st

在使用
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;
}
我希望输出是

hello world
HELLO WORLD
但我只是

hello world
hello world
我使用
printf
对其进行了测试,因为我认为这可能是
cout
的工作方式所特有的,但我得到了相同的结果,所以我想我的代码可能有问题。
我的代码有什么问题?

问题是“何时调用函数”以及如何处理引用。由于它是一个缓冲流,它似乎在调用它们,可能是无序的。如果删除返回字符串的引用(因此为每个函数返回一个新的唯一字符串),代码将正常工作

void toLower(string &str)
{
    for(char &c : str)
        c = tolower(c);

    return str;
}

void toUpper(string &str)
{
    for(auto &c : str)
        c = toupper(c);
}

您正在修改表达式求值中的变量(字符串),并依赖于在求值过程中的某些点使用该变量。正如你所发现的,你不能依赖它

一种解决方案是使用不同的字符串;另一个可能是打破表达:

cout << toLower(str) << endl;
cout << toUpper(str) << endl;

<代码> CUT< P>这是C++分析你的语句的方式:

cout << toLower(str) << endl << toUpper(str) << endl; //str = Hello World

cout对
operator的调用返回一个副本而不是一个引用,如果您两次操作同一个字符串,它就会工作得很好。Cout是缓冲的,所以我猜这就是导致问题的原因。因此,给定
Cout
行,在什么时候调用哪个函数?我让你回答你自己的问题。printf示例更容易推理。给定一个函数
f(x,y)
,调用它时,首先计算两个参数。由于您的函数通过引用获取并返回,所以最后一个函数“获胜”。如果您想在适当的位置操作字符串,请使您的函数返回void,然后执行
toLower(str);你不仅不能依赖它,这显然是一种未定义的行为。就像
i=i++
是一样。@Ven:不能依赖某个特定的行为,这意味着什么是未定义的?不。计算顺序未定义–在
a(b(),c())
中,您不能依赖于在
c()
之前运行
b()
,但没有未定义的行为。也可能是impl定义的行为。@Ven,否,求值顺序未指定,未定义,这里没有未定义的内容,一个函数调用顺序排在另一个之前,因此它与
i=i++
不同。它是未指定的,在另一个之前排序,但仍然没有未定义的内容。减1–修改字符串后返回一个副本。这是没有道理的,它与缓冲无关。修改字符串的函数调用都是在写入流之前进行计算的。感谢您的详细解释和一些背景信息。事实上,我期待着第三种解决方案的出现。太糟糕了,没有为这种情况指定定义的行为。
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
cout <<"hello world\nhello world\n";
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;