结构绑定的std :: tuple中断std :: stringstream

时间:2019-03-17 15:31:44

标签: c++ stringstream stdtuple

考虑以下代码:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <tuple>

auto read_data(std::ifstream& training_file) {
    if (!training_file) {
        throw std::runtime_error{"Error: could not open one or more files"};
    }

    std::stringstream training{};
    training << training_file.rdbuf();

    std::cout << training.str() << '\n';

    return std::tie(training);
}

int main() {
    std::ifstream input{"input.txt"};

    auto [train] = read_data(input);

    std::cout << train.str() << '\n';
    std::cout << "x" << '\n';
}

并且忽略以下事实:我将返回一个带有std::tie的元素(最初我是tie带有两个std::stringstream对象,但是MCVE不需要)。

input.txt文件如下所示:

0,0,0,0,
0,0,0,0,

注意-第二行之后没有换行符。

该程序的意外输出是:

0,0,0,0,
0,0,0,0,
É$~      Ź     ,
x

很显然,É$~ Ź ,部分不应该在那里。

请注意,我正在输出完全相同的文件内容。我不知道意外部分来自哪里。

在玩代码时变得更加陌生。如果我在std::cout << train.str() << '\n';中注释掉main(),并在std::cout << training.str() << '\n';函数中复制了read_data()行,则输出是预期的:

0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
x

因此两次调用std::stringstream::str不会引起这种情况。这一定是由于使用返​​回值引起的。

还有什么?从std::cout << train.str() << '\n'; 两次执行main()行会导致code 3终止程序。

GDB报告:

gdb: unknown target exception 0x80000001 at 0x7ff909e845c0
Thread 1 received signal ?, Unknown signal.
0x00007ff909e845c0 in ?? ()

但是仍然没有在这里结束。如果我将文件内容更改为包含以下任一内容:

0 0

0 0 0 0
0 0 0 0

输出再次符合预期(使用原始代码-cout中的一个read_data()main()中的一个。

为确保不会被隐藏在文件中的某些不可打印字符所欺骗,我使用PowerShell输出其十六进制表示形式,这导致以下有关原始文件内容的序列:

30 20 30 20 30 20 30 0D 0A 30 20 30 20 30 20 30

如您所见,我的文件中没有0,空格和carriage-return + line-feed

知道为什么会这样吗?有关完整信息,我正在使用MinGW的GCC 8.2.0。

1 个答案:

答案 0 :(得分:4)

这是本地的:

std::stringstream training{};

这将返回对表示为本地的引用,并包装在元组中:

return std::tie(training);

因此auto [train] = ...;将名称train初始化为悬挂的引用。该程序的行为是不确定的。


如果您需要返回两个流(或更多),则只需在您选择的元组/数组/自定义聚合中预先声明它们即可:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <tuple>
#include <array>

auto read_data() {
    std::array<std::stringstream,2> trainings{
        std::stringstream{},
        std::stringstream{}
    };

    return trainings;
}

int main() {

    auto train = read_data();

    std::cout << train[1].str() << '\n';
    std::cout << "x" << '\n';
}

Live Code

复制省略确保多余的对象将被完全删除或移动到位。