c++ - 用 nullptr 交换流缓冲区来模拟移动?

标签 c++ stream

我想在一个结构中存储一个 std::istream 并能够从另一个流构造它。目前,我有以下内容:

struct A {
    A(std::istream &in) : in_(in.rdbuf()) { }
protected:
    std::istream in_;
};

这只允许从已创建的对象创建类型为 A 的对象,但我希望能够执行以下操作:

A(std::stringstream("hello world!"));

我为 std::istream 的右值引用添加了以下 A 重载:

A(std::istream &&in) : in_(in.rdbuf()) {
    in.rdbuf(nullptr); // (1)
}

我添加了 (1) 以避免缓冲区在序列点之后被销毁,但我不知道是否定义了此行为或者这是否真的有意义?

我可以根据标准像这样“移动”流缓冲区吗?如果不是,这是否适用于标准实现和流(std::stringstreamstd::fstream、...)?

最佳答案

最好避免处理缓冲区并让对象在内部为我们完成工作。

我提出以下建议。使用模板,我们可以确保在将流移动到结构中时构造完整类型的共享指针。

#include <sstream>
#include <iostream>
#include <fstream>
#include <memory>
#include <typeinfo>

struct A {
    template<typename T>
    A(T& is) : is{is}
    {
        std::cout << "Only taking a reference. Not taking ownership of std::istream.\n";
    }

    template<typename T>
    A(T&& is) : own_is{std::make_unique<T>(std::move(is))}, is{*own_is}
    {
        std::cout << "using move. Not sliced.\n";
    }

    void print_stream_type()
    {
        std::cout << typeid(is).name() << '\n';
    }
protected:
    std::unique_ptr<std::istream> own_is;
    std::istream& is;
};

int main()
{
    A a1{std::stringstream{"hello world!"}};

    A a2{std::cin};

    std::ifstream ifs{"input.txt"}; 
    A a3{ifs};

    A a4{std::ifstream{"input.txt"}};

    a1.print_stream_type();
    a2.print_stream_type();
    a3.print_stream_type();
    a4.print_stream_type();

}

MSVC2017 上的输出:

using move. Not sliced.
Only taking a reference. Not taking ownership of std::istream.
Only taking a reference. Not taking ownership of std::istream.
using move. Not sliced.
class std::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> >
class std::basic_istream<char,struct std::char_traits<char> >
class std::basic_ifstream<char,struct std::char_traits<char> >
class std::basic_ifstream<char,struct std::char_traits<char> >

另请注意结构中成员的顺序很重要。如果 A 是通过引用构造的,则 own_is 变量将为 null。但是,如果我们传递一个右值,那么它将首先创建共享指针,然后取消引用它以传递一个有效的引用。在这两种情况下,相同的引用指向流。

关于c++ - 用 nullptr 交换流缓冲区来模拟移动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44803572/

相关文章:

php - 在 PHP 上运行 C++ 可执行文件

c++ - std::wstring_convert 和 std::wbuffer_convert 有什么区别?

json - 如何在不将整个数组加载到内存的情况下从包含 json 数组的流中一次读取一个 json 对象?

node.js - 通过stream.end()后重新打开写入流

c++ - 根据参数数量从函数返回结构对象并将其分配给一般结构的对象

c++ - Qt中如何访问其他类的对象?

c++ - std::copy 用于多维数组

reactjs - 如何从 fetch 请求中的 readableStream 响应中获取可下载文件

node.js - Node 中读取流的新方式会导致阻塞吗?

C++ 试图忽略文件的一部分?