How do I check if a StringStream variable is empty/null?

前端 未结 8 840
粉色の甜心
粉色の甜心 2020-12-13 08:32

Just a quick question here guys. I\'ve been searching to no avail so far.

A bit more info here:

stringstream report_string;

report_string << \         


        
相关标签:
8条回答
  • 2020-12-13 08:54

    I know that this question is very old and already answered, but depending on the situation there might also be yet another approach worth considering:

    When you are testing if a stringstream is empty, you properly intend to do something with either the individual strings or each line in the stringstream; thus you will most likely be using either the >> operator or std::getline on the stringstream... and if the stream is empty these simply have the value false, thus you could write:

    stringstream report_string;
    
    foo(report_string)// some functions which may or may not write to report_string
    
    string single_report;//string to read to
    
    bool empty=true;//First assume it was empty
    while(getline(report_string,single_report))//Alternatively use report_string>>single_report if you don't want entire lines
    {
        empty=false;//...it wasn't empty
        bar(single_report);//Do whatever you want to do with each individual appended line 
    }
    
    if (empty)
    {
        //... whatever you want to do if the stream was empty goes here
    }
    

    It should be noted that this approach assumes that you were planning on cycling through the stringstream; if you were not, then this approach can't be used.

    0 讨论(0)
  • 2020-12-13 08:56

    One way would be to check the size of the internal string and compare against zero. Note that this is different from myStream.rdbuf()->in_avail() as AusCBlock suggests; in_avail() can return a value different from the actual size of the stream (if, for example, the internal buffer is represented with multiple non-contiguous memory blocks). In particular, in_avail() can, in principle, return zero in non-empty buffers (it's possible that the stringbuf specification restricts this further; I have no checked in that much detail).

    0 讨论(0)
  • 2020-12-13 09:03

    An easy check would be to see if the string content of the stream is empty or not:

    #include<assert.h>
    #include<sstream>
    
    int main(){
    std::stringstream report_string;
    report_string << ""; // an empty strin g
    
    //emptiness check of stringstream
    assert(report_string.str().empty());
    }
    
    0 讨论(0)
  • 2020-12-13 09:13

    myStream.rdbuf()->in_avail() can be used to get the count of available characters ready to be read in from a stringstream, you can use that to check if your stringstream is "empty." I'm assuming you're not actually trying to check for the value null.

    For example if you want to extract an int from a stringstream and then see if there were any left over characters (ie. non-numeric) you could check if myStream.rdbuf()->in_avail() == 0.

    Is that something similar to what you're trying to do? I'm not sure if there's better ways but I've done this in the past and it's worked fine for me.

    https://en.cppreference.com/w/cpp/io/basic_streambuf/in_avail

    EDIT: I see you just updated your question as I posted.

    0 讨论(0)
  • 2020-12-13 09:16

    How about another approach?

    If you make the ostringstream an optional type you can check that its been assigned to before using it.

    Imagine a class called lazy<> which lazily constructs an object when needed, then we could do this:

    int main()
    {
        using namespace std;
    
        auto oss1 = lazy<std::ostringstream>();
        auto oss2 = lazy<std::ostringstream>();
    
        use(oss1) << "Hello";
    
        if (oss1) cout << use(oss1).str() << endl;
        if (oss2) cout << use(oss2).str() << endl;
    
        if_used(oss1, [](auto& ss) { cout << ss.str() << endl; });
        if_used(oss2,
                [](auto& ss) { cout << ss.str() << endl; },
                [](auto& oss) { cout << "oss2 is not used" << endl; });
    
        use(oss2) << "Goodbye";
        if_used(oss2, [](auto& ss) { cout << ss.str() << endl; });
    
        return 0;
    }
    

    yielding this output:

    Hello
    Hello
    oss2 is not used
    Goodbye
    

    Advantages:

    • no redundant construction of the stringstream when not used.

    • optional provides an exception if the unused stringstream is subsequently used (via const reference)

    Full example below with customisable constructor:

    I've used std::experimental for the optional, but you could just as easily use boost::optional.

    #include <iostream>
    #include <experimental/optional>
    #include <utility>
    #include <type_traits>
    #include <sstream>
    
    using std::experimental::optional;
    
    namespace detail {
        template<class T, class Constructor>
        struct lazy final
        {
            template<class Con , std::enable_if_t< not std::is_same<std::decay_t<Con>, lazy>::value > * = nullptr>
            lazy(Con&& con)
            : _constructor(std::forward<Con>(con))
            {}
    
            T& get() {
                if (not bool(_opt)) {
                    _opt = _constructor();
                }
                return *_opt;
            }
    
            const T& get() const {
                return *_opt;
            }
    
            bool used() const {
                return bool(_opt);
            }
    
            operator bool() const {
                return used();
            }
    
        private:
            Constructor _constructor;
            optional<T> _opt;
        };
    
        template<class T>
        struct default_construct {
            T operator()() const { return T(); }
        };
    
        struct no_action {
            template<class T>
            void operator()(T&) const { }
        };
    }
    
    
    template<class T, class Constructor = detail::default_construct<T> >
    auto lazy(Constructor&& con = detail::default_construct<T>())
    {
        return detail::lazy<T, std::decay_t<Constructor>>(std::forward<Constructor>(con));
    }
    
    template<class T, class Constructor>
    auto& use(detail::lazy<T, Constructor>& l)
    {
        return l.get();
    }
    
    template<class T, class Constructor>
    auto& use(const detail::lazy<T, Constructor>& l)
    {
        return l.get();
    }
    
    template<class T, class Constructor, class F, class Else = detail::no_action>
    void if_used(detail::lazy<T, Constructor>& l, F&& f, Else&& e = detail::no_action())
    {
        if (l.used())
            f(l.get());
        else
            e(l);
    }
    
    template<class T, class Constructor, class F, class Else = detail::no_action>
    void if_used(const detail::lazy<T, Constructor>& l, F&& f, Else&& e)
    {
        if (l.used())
            f(l.get());
        else
            e(l);
    }
    
    int main()
    {
        using namespace std;
    
        auto oss1 = lazy<std::ostringstream>();
        auto oss2 = lazy<std::ostringstream>();
    
        use(oss1) << "Hello";
    
        if (oss1) cout << use(oss1).str() << endl;
        if (oss2) cout << use(oss2).str() << endl;
    
        if_used(oss1, [](auto& ss) { cout << ss.str() << endl; });
        if_used(oss2,
                [](auto& ss) { cout << ss.str() << endl; },
                [](auto& oss) { cout << "oss2 is not used" << endl; });
    
        use(oss2) << "Goodbye";
        if_used(oss2, [](auto& ss) { cout << ss.str() << endl; });
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-13 09:19

    It's normally reasonable and readable to use...

    report_string.str().empty()
    

    ...but that may involve dynamic allocation and copying the entire string to a temporary, only to be thrown away.

    If performance is important, another option is...

    report_string.peek() == decltype(report_string)::traits_type::eof()
    
    • this looks for a character not yet extracted from the stream, ignoring input that's already been successfully parsed/extracted

      • that's different from testing report_string.str().empty(), which still "sees" already-extracted input
    • if earlier parsing left the stream in a fail state you haven't clear()ed, this will return eof() regardless of whether there are more unextracted characters

    0 讨论(0)
提交回复
热议问题