简体   繁体   中英

Using std::unique_ptr with std::istream?

I am writing a program in c++ that can take input from a file (passed to it as a command line arg), from std::cin, or std::istringstream. It works fine, and is managed with with an std::istream*. I was told this was bad, handling raw pointers, so i decided to wrap it in an std::unique_ptr (ie std::unique_ptr). The problem is it won't compile. As far as i can discern from the errors, std::istream has protected itself from being used to allocate memory. I've tried googling it, but I don't think someone has posted a question like this before (since I only saw questions referring to just std::unique_ptr). Does anyone know how to achieve this?

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

in response to this line: std::unique_ptr Stream(new std::istream());

I have also tried it without invoking the istreams constructor and without anything in the unique_ptrs contructor

edit 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;
}

I'd say this is just very poorly factored code. Why not have it like this:

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;
    }
}

The error you are showing is due to the std::istream constructor call, its a base class and can't be instantiated. Even if the code did compile, std::unique_ptr is an owning pointer so ther would be issues attempting to delete std::cin. You want a non-owning pointer so either a raw pointer or std::weak_ptr is correct.

EDIT: I would suggest using references instead, if possible.

I often go about selecting streams like this:

#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
    }
}

That's how I avoid using pointers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM