简体   繁体   English

奇怪的cout行为

[英]Weird cout behaviour

I noticed a rather strange behaviour when using std::cout for outputting something to the console. 当使用std::cout向控制台输出内容时,我注意到了一个相当奇怪的行为。
I wrote two functions string& toUpper(std::string &str) and string& toLower(std::string &str) which should do exactly what they are called after: Convert a string all uppercase or all lowercase. 我写了两个函数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;
}

Now I tested both functions independently and they are working as expected. 现在我独立测试了这两个功能,它们按预期工作。 Then I chained both of them in a cout call: 然后我在一个cout电话中链接了他们两个:

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

I expected the output to be 我期待输出

hello world
HELLO WORLD

but instead I just got 但我只是得到了

hello world
hello world

I tested the same using printf because I thought it might be something specific to cout 's way of doing stuff but I got the same result, so I guess I got something wrong with my code. 我使用printf进行了同样的测试,因为我认为这可能是cout做事的方式特有的但我得到了相同的结果,所以我猜我的代码出了点问题。
What's the problem with my code? 我的代码有什么问题?

You are modifying a variable (the string) within the evaluation of an expression, and are relying on it being used at certain points during that evaluation. 您正在修改表达式求值中的变量(字符串),并且依赖于在评估期间的某些点使用它。 As you have found, you can't rely on that. 正如您所发现的那样,您不能依赖它。

One solution would be to use different strings; 一种解决方案是使用不同的字符串; another would be to break up the expression: 另一个是打破表达:

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

Its the way c++ parses your statement: 它是c ++解析你的语句的方式:

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

1st step evaluate toUpper: 第一步评估为上:

cout << toLower(str) << endl << str << endl;//str = HELLO WORLD

2nd step evaluate toLower: 第二步评估到下:

cout << str << endl << str << endl;//str = hello world

3rd step evaluate cout: 第3步评估cout:

cout <<"hello world\nhello world\n";

The reason your cout produces this result is because it is modifing the same string before printing. 你的cout产生这个结果的原因是因为它在打印之前修改了相同的字符串。 Use a copy instead of a reference to fix this. 使用副本而不是引用来修复此问题。

The calls to operator<< must happen in order, left-to-right, but the C++ standard does not specify the order of evaluation of sub-expressions within the statement. operator<<的调用必须按顺序从左到右进行,但C ++标准没有指定语句中子表达式的求值顺序。

The compiler can decide in which order to evaluate the sub-expressions, so that any of these outcomes is valid: 编译器可以决定评估子表达式的顺序,以便任何这些结果都是有效的:

auto&& arg1 = toLower(str);
auto&& arg2 = toUpper(str);
cout << arg1 << endl << arg2 << endl;

Or: 要么:

auto&& arg1 = toUpper(str);
auto&& arg2 = toLower(str);
cout << arg2 << endl << arg1 << endl;

Or: 要么:

auto&& arg1 = toUpper(str);
auto&& arg2 = (cout << arg1);
auto&& arg3 = toUpper(str);
arg2 << endl << arg3 << endl;

Or several other possibilities. 或其他几种可能性。 Of these three possible sequencings, only the last one would produce the result you expect. 在这三种可能的顺序中,只有最后一种顺序会产生您期望的结果。 The first case would result in "HELLO WORLD" being printed twice, and the second case is the result you get with your compiler. 第一种情况会导致“HELLO WORLD”打印两次,第二种情况是您使用编译器得到的结果。 All are valid outcomes according to the C++ standard. 根据C ++标准,所有都是有效的结果。

The issue is "when it is calling the function" and how the reference is being processed. 问题是“何时调用函数”以及如何处理引用。 As it is a buffered stream, it seems to be calling them possibly out of order. 由于它是一个缓冲流,它似乎可能无序地调用它们。 If you remove the reference for the returned string (So you are returning a new unique string for each function) the code works properly. 如果删除返回的字符串的引用(因此,您为每个函数返回一个新的唯一字符串),代码将正常工作。

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

    return str;
}

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM