为什么std :: string连接运算符的工作方式类似于右关联运算符?

时间:2014-09-15 07:33:20

标签: c++ string gcc visual-c++-2012

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

#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("line1\nline2\nline3");
    InputStringStream stream(s);
    std::cout << stream.readLine() + "\n" + stream.readLine() + "\n" + stream.readLine() << std::endl;
    return 0;
}

产生以下输出

line3
line2
line1

虽然我期待

line1
line2
line3

我做错了什么?

P.S。使用Apple LLVM编译器版本5.1编译的相同代码产生了我的期望。 Visual C ++ 2012在GCC方面。

3 个答案:

答案 0 :(得分:16)

函数参数的评估顺序是未指定,所以你做错了就是持有错误的,毫无根据的信念和期望。 (像+<<这样的重载运算符只是普通的函数调用。)

您必须以确定的顺序提取流元素,并且 负责这样做。例如:

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'; }

答案 1 :(得分:11)

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

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

未指定首先调用stream.readLine()

答案 2 :(得分:4)

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

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