【问题标题】:Using std::unique_ptr with std::istream?将 std::unique_ptr 与 std::istream 一起使用?
【发布时间】:2014-08-29 20:32:56
【问题描述】:

我正在用 c++ 编写一个程序,它可以从文件(作为命令行参数传递给它)、std::cin 或 std::istringstream 获取输入。它工作正常,并使用 std::istream* 进行管理。有人告诉我这很糟糕,处理原始指针,所以我决定将它包装在 std::unique_ptr (即 std::unique_ptr )中。问题是它不会编译。据我从错误中可以看出,std::istream 已保护自己不被用于分配内存。我试过用谷歌搜索它,但我认为以前没有人发布过这样的问题(因为我只看到仅指 std::unique_ptr 的问题)。有谁知道如何做到这一点?

edit: errors: In file included from /usr/include/c++/4.8/iostream:40:0,
                 from /home/dtscode/Desktop/SLang/src/main.cpp:1:
/usr/include/c++/4.8/istream: In function ‘int main(int, char**)’:
/usr/include/c++/4.8/istream:606:7: error: ‘std::basic_istream<_CharT, _Traits>::basic_istream() [with _CharT = char; _Traits = std::char_traits<char>]’ is protected
       basic_istream()
       ^
compilation terminated due to -Wfatal-errors.
make[2]: *** [CMakeFiles/slang.dir/src/main.cpp.o] Error 1
make[1]: *** [CMakeFiles/slang.dir/all] Error 2
make: *** [all] Error 2

响应这一行:std::unique_ptr Stream(new std::istream());

我也尝试过,没有调用 istreams 构造函数,并且在 unique_ptrs 构造函数中没有任何内容

编辑 2:

#include <iostream>
#include  <fstream>
#include  <sstream>
#include   <vector>
#include   <string>
#include   <memory>

#include <lexer.hpp>

int main(int argc, char *argv[]) {
    std::unique_ptr<std::istream> Stream(new std::istream());
    std::vector<std::string> Arguments(argv, argv + argc);

    switch(argc) {
        case 1:
            Stream = &std::cin;
            break;

        case 2:
            Stream = new std::ifstream(Arguments[1]);
            break;

        case 3:
            if(Arguments[1] == "-c") {
                Stream = new std::istringstream(Arguments[2]);
                break;
            }

        default:
            std::cerr<<"error: invalid arguments."<< std::endl;
            return 0;
    }

    Token::Lexeme CurrentToken = Token::Start;

    while(*Stream) {
        CurrentToken = getToken(Stream);
        lex_debug();
    }

    if(Stream != &std::cin) {
        delete Stream;
    }

    return 0;
}

【问题讨论】:

  • “有人告诉我这很糟糕,处理原始指针” -- 你问过为什么吗?给出了什么理由?
  • 是的。他们说处理原始指针和使用 stl 解决方案很危险
  • 您应该要求他们更具体。无论如何,您的用例是使用原始指针的一个很好的例子。也就是说,作为非拥有的、可重新分配的参考。如果您不需要重新分配它,您可以使用引用,但代码会有点复杂,因为引用必须在创建时绑定。
  • 你为什么需要istream*为什么不直接使用std::istream
  • @Ben:因为他正在尝试使用运行时多态性。

标签: c++ c++11 stl unique-ptr istream


【解决方案1】:

我会说这只是分解得很差的代码。为什么不这样:

void process_input(std::istream & is);

int main(int argc, char * argv[]) {
    if (argc == 1) {
        process_input(std::cin);
    } else if (argc == 2) {
        std::ifstream is(argv[1], "rb");
        process_input(is);
    } else if (argc == 3 && strcmp(argv[1], "-c") == 0) {
        std::istringstream is(argv[2]);
        process_input(is);
    } else {
        std::cerr << "Unrecognized invocation.\n";
        return EXIT_FAILURE;
    }
}

【讨论】:

  • 为什么这个比我的好?
  • @DTSCode: a) 它可以编译,b) 它没有奇怪的所有权混淆,c) 将驱动程序代码与逻辑分开,d) 逻辑代码可以单独测试,e) 复杂性较低,更具可读性,f) 独角兽。
  • @BenjaminLindley:只有 iostreams has made me wantstd::move 相反,即 template &lt;typename T&gt; T &amp; stay(T &amp;&amp; x) { return x; }
  • 好吧,我只是好奇。但是,如果我不把它放在 unique_ptr 中,它可以正常工作/编译
  • @DTSCode:我对“工作正常”或“完美工作”的代码有我的个人看法,但适合自己。这是你的代码库。
【解决方案2】:

您显示的错误是由于 std::istream 构造函数调用,它是一个基类并且无法实例化。即使代码确实编译了,std::unique_ptr 也是一个拥有指针,因此尝试删除 std::cin 会出现问题。您想要一个非拥有指针,因此原始指针或 std::weak_ptr 都是正确的。

编辑:如果可能的话,我建议使用引用。

【讨论】:

  • 基类可以被实例化。 Abstract 类不能。
【解决方案3】:

我经常这样选择流:

#include <iostream>
#include <fstream>
#include <istream>
#include <sstream>
#include <vector>

int main(int argc, char *argv[])
{
    std::vector<std::string> args(argv, argv + argc);

    std::ifstream ifs(argc == 2 ? args[1]:"");
    std::istringstream iss(argc == 3 ? args[2]:"");

    std::istream& is = argc == 2 ? ifs : argc == 3 && args[1] == "-c" ? iss : std::cin;

    while(is)
    {
        // process stream
    }
}

这就是我避免使用指针的方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-04
    • 2011-06-05
    • 2021-05-02
    相关资源
    最近更新 更多