结构绑定 std::tuple 中断 std::stringstream
Structure-bound std::tuple breaks std::stringstream
考虑以下代码:
#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
ing 两个 std::stringstream
对象,但 MCVE 不需要)。
input.txt
文件如下所示:
0,0,0,0,
0,0,0,0,
注意 - 第二行后没有换行符。
这个程序的意外输出是:
0,0,0,0,
0,0,0,0,
É$~ Ź ,
x
显然,É$~ Ź ,
部分不应该存在。
请注意,我正在输出完全相同的文件内容。我不知道意外的部分是从哪里来的。
玩代码的时候就更奇怪了。如果我注释掉 main()
中的 std::cout << train.str() << '\n';
并复制 read_data()
函数中的 std::cout << training.str() << '\n';
行,则输出符合预期:
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
x
所以它不是调用 std::stringstream::str
两次引起的。肯定是返回值的使用引起的
还有什么?从 main()
执行 std::cout << train.str() << '\n';
行两次 导致程序终止 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
输出再次符合预期(使用原始代码 - read_data()
中的一个 cout
和 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。
这是本地的:
std::stringstream training{};
这个 return 是对所述本地的引用,包含在一个元组中:
return std::tie(training);
因此 auto [train] = ...;
将名称 train
初始化为悬空引用。程序的行为未定义。
如果您需要 return 两个流(或更多),那么只需在您选择的 tuple/array/custom 集合中预先声明它们:
#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';
}
复制省略保证额外的对象将被完全删除或移动到适当的位置。
考虑以下代码:
#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
ing 两个 std::stringstream
对象,但 MCVE 不需要)。
input.txt
文件如下所示:
0,0,0,0, 0,0,0,0,
注意 - 第二行后没有换行符。
这个程序的意外输出是:
0,0,0,0, 0,0,0,0, É$~ Ź , x
显然,É$~ Ź ,
部分不应该存在。
请注意,我正在输出完全相同的文件内容。我不知道意外的部分是从哪里来的。
玩代码的时候就更奇怪了。如果我注释掉 main()
中的 std::cout << train.str() << '\n';
并复制 read_data()
函数中的 std::cout << training.str() << '\n';
行,则输出符合预期:
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, x
所以它不是调用 std::stringstream::str
两次引起的。肯定是返回值的使用引起的
还有什么?从 main()
执行 std::cout << train.str() << '\n';
行两次 导致程序终止 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
输出再次符合预期(使用原始代码 - read_data()
中的一个 cout
和 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。
这是本地的:
std::stringstream training{};
这个 return 是对所述本地的引用,包含在一个元组中:
return std::tie(training);
因此 auto [train] = ...;
将名称 train
初始化为悬空引用。程序的行为未定义。
如果您需要 return 两个流(或更多),那么只需在您选择的 tuple/array/custom 集合中预先声明它们:
#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';
}
复制省略保证额外的对象将被完全删除或移动到适当的位置。