为什么std::字符串串联运算符的工作原理类似于右关联运算符

Why std::string concatenation operator works like right-associative one?

本文关键字:运算符 类似于 关联 工作 字符串 为什么 std      更新时间:2023-10-16

运行以下从我的宠物项目中提取并使用GCC 4.9.1(以及4.8.1)编译的MWE

#include <iostream>
#include <string>
#include <sstream>
class InputStringStream
{
public:
    InputStringStream(const std::string& str) : istringstream(str), currentLine() {}
    std::string readLine()
    {
        std::getline(istringstream, currentLine);
        return currentLine;
    }
private:
    std::istringstream istringstream;
    std::string currentLine;
};
int main()
{
    std::string s = std::string("line1nline2nline3");
    InputStringStream stream(s);
    std::cout << stream.readLine() + "n" + stream.readLine() + "n" + stream.readLine() << std::endl;
    return 0;
}

产生以下输出

line3
line2
line1

而我期待

line1
line2
line3

我做错了什么?

附言:使用Apple LLVM编译器5.1版编译的相同代码产生了我所期望的结果。Visual C++2012在GCC方面。

函数参数的求值顺序是未指定,所以你做错的是持有错误的、不必要的信念和期望。(像+<<这样的重载运算符只是普通的函数调用。)

你必须以确定的顺序提取流元素,这是的责任。例如:

std::cout << stream.readLine() + 'n';
std::cout << stream.readLine() + 'n';
std::cout << stream.readLine() + 'n';

更好的是,避免冗余和临时字符串:

for (auto i : { 1, 2, 3 }) { std::cout << stream.readLine() << 'n'; }

问题不在于关联性,在这个表达式中:

stream.readLine() + "n" + stream.readLine() + "n" + stream.readLine() 

未指定先调用哪个stream.readLine()

唯一错误的是假设在一个调用stream.readLine()三次的表达式中,这些表达式的出现顺序与调用顺序匹配。有些编译器可能会先对最后一个调用求值,有些则可能会按顺序求值。理论上,有些人甚至可能会先评估中间的一个。这只是C++的一个一般规则:表达式的求值顺序是不指定的。

在所有实现中获得相同结果的一个简单方法是将这三个结果存储在单独的变量中。