如何耦合两个变量的生命周期?

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)

Pio*_*ycz 2

正如一条评论所建议的,将流及其迭代器结合在一个结构中 - 以确保迭代器不会比流寿命长:

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)

  • *“您不能将 `FileIter x(p1);` 替换为 `auto x = FileIter(p1).iter;`”*。但是通过[生命周期扩展](https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary)(来自子对象),`auto&amp;&amp; x = FileIter(p1).iter;`将是可能的。 (3认同)