从函数返回istream的正确方法

时间:2019-12-22 19:39:59

标签: c++ pointers reference istream

我正在测试istream各种数据读取技术的速度,因此我创建了一个从文件重复创建istream的功能,因此被测试的下一种方法可以使用该istream。

using std::istream;
using std::string;

istream* getStreamFrom(string filepath)
{
    std::filebuf init_buffer;
    if (init_buffer.open(filepath, std::ios::in))
    {
        std::istream inputStream(&init_buffer);
        init_buffer.close();
        return &inputStream;
    }

    // file not found
    istream inputStream(0);
    return &inputStream;
}

然后我将istream传递给经过测试的方法,如下所示:

istream* data = getStreamFrom(FILEPATH);
someMethod(*data);

但是在someMethod中,从istream读取时出现访问冲突:

void someMethod(istream& input)
{
    string line;
    while (std::getline(input, line))    // code failes here
        // do something
}

为什么会这样,我该如何解决?不论是否找到文件都没有关系,在两种情况下都会发生。

2 个答案:

答案 0 :(得分:1)

如果要从函数返回本地流,则需要同时动态分配流及其缓冲区。正如注释和答案所解释的那样,您正在返回指向局部变量的指针,该局部变量将在函数退出后销毁。标准流类.commitNow()std::istream是不可移动的,因此您唯一的选择是在堆上创建对象。流和缓冲区都可以包装在一个智能指针中,以避免人工管理内存。

std::ostream

std::unique_ptr<std::istream> getStreamFrom(std::string filepath) { auto init_buf = std::make_unique<std::filebuf>(); return std::make_unique<std::istream>( init_buf->open(filepath, std::ios_base::in) ? init_buf.release()->close() : nullptr ); } 初始化的std::istreamstd::filebuf。您还可以返回一个指向它的指针:

std::fstream

在C ++ 17中具有可选功能:

std::unique_ptr<std::ifstream> getStreamFrom(std::string filepath) {
  auto stream = std::make_unique<std::ifstream>(filepath);
  stream->close();
  return std::unique_ptr<std::ifstream>( *stream ? std::move(stream) : nullptr );
}

答案 1 :(得分:0)

一旦您的函数退出,

inputStream就会进入我们的范围。在函数外部访问std::istream*将导致未定义的行为。

可能最好的方法是使用std::shared_ptr。像这样:

std::shared_ptr<std::istream> getStreamFrom(string filepath)
{
    std::filebuf init_buffer;
    if (init_buffer.open(filepath, std::ios::in))
    {
        std::shared_ptr<std::istream> inputStream = std::make_shared<std::istream>(&init_buffer);
        init_buffer.close();
        return inputStream;
    }

    // file not found
    std::shared_ptr<std::istream> inputStream = std::make_shared<istream>(nullptr);
    return inputStream;
}

当然,init_buffer也将超出范围。不确定passing it directly into std::istream won't delete the buffer是正确的做法。我不知道正确的方法是在这里,因为您不是自己制作std::istream,因此建议的解决方案对您不起作用。因此,您对此感到有点自己。但是你已经被警告了。

您可以做的一件事是std::move()。这是一些more information on std::move()ing things