10

运行从我的宠物项目中提取并使用 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("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

我做错了什么?

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

4

3 回答 3

16

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

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

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'; }
于 2014-09-15T07:38:30.530 回答
11

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

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

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

于 2014-09-15T07:38:58.967 回答
4

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

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

于 2014-09-15T07:38:37.963 回答