ber*_*ers 5 c++ scope lifetime
以下代码编译并运行良好,但未按预期工作(比较代码中的注释)。我相信原因是 的生命周期is以 结束getFileIter,因此流缓冲区迭代器没有什么可以迭代的。(相比之下,我想我记得在 C# 中,is只要流缓冲区迭代器指向它,它就会存在,但在 C++ 中似乎并非如此。)
避免这种情况的一种解决方法是使用... *is = new std::ifstream(p),但这意味着完成后我必须自己处理指针。
是否有任何机制可以链接is其流缓冲区迭代器的生命周期?
// g++ test.cpp -o test && ./test
#include <iostream>
#include <fstream>
std::istreambuf_iterator<char> getFileIter(std::string p)
{
std::ifstream is(p);
//std::ifstream *is = new std::ifstream(p);
std::cout << "Read " << p << "? " << is.good() << std::endl;
return std::istreambuf_iterator<char>(is.rdbuf());
}
int main()
{
std::string p1("/etc/passwd");
std::string p2("/etc/group");
// Prints 1 as if the two files were identical
std::cout << std::equal(
getFileIter(p1),
std::istreambuf_iterator<char>(),
getFileIter(p2)
) << std::endl;
// Prints nothing except /////
auto x = getFileIter(p1);
int i = 0;
do
{
std::cout << *(x++) << "/";
i++;
} while (i < 5);
std::cout << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
正如一条评论所建议的,将流及其迭代器结合在一个结构中 - 以确保迭代器不会比流寿命长:
struct FileIter
{
FileIter(const std::string& p)
: is(p), iter(is.rdbuf())
{}
std::ifstream is;
std::istreambuf_iterator<char> iter;
};
std::cout << std::equal(
FileIter(p1).iter,
std::istreambuf_iterator<char>(),
FileIter(p2).iter
) << std::endl;
FileIter x(p1);
int i = 0;
do
{
std::cout << *(x.iter++) << "/";
i++;
} while (i < 5);
std::cout << std::endl;
Run Code Online (Sandbox Code Playgroud)
如果你愿意 - 你可以让它FileIter看起来像迭代器 - 请参阅这篇文章
两件重要的事情:
在此代码中:
std::cout << std::equal(
FileIter(p1).iter,
std::istreambuf_iterator<char>(),
FileIter(p2).iter
) << std::endl;
Run Code Online (Sandbox Code Playgroud)
FileIter可能是临时的(无名的),因为它的生命周期保证与表达式末尾(分号)一样长。
在这里,您不能替换FileIter x(p1);为auto x = FileIter(p1).iter;,因为流输入FileIter将随着表达式的结束(此处为分号)而结束其生命周期。
FileIter x(p1);
int i = 0;
do
{
std::cout << *(x.iter++) << "/";
i++;
} while (i < 5);
std::cout << std::endl;
Run Code Online (Sandbox Code Playgroud)