如何检查StringStream变量是否为空/ null?

时间:2011-11-08 05:32:51

标签: c++

这里只是一个简单的问题。到目前为止,我一直在寻找无济于事。

谢谢!

这里有更多信息:

stringstream report_string;

report_string << "some string here...";

在我的代码中,有各种条件为report_string变量赋值。

我想检查一下是否分配了值。

8 个答案:

答案 0 :(得分:43)

myStream.rdbuf()->in_avail()可用于获取可以从stringstream读入的可用字符数,您可以使用它来检查stringstream是否为“空”。我假设您实际上并没有尝试检查值null

例如,如果您要从int中提取stringstream,然后查看是否有任何遗留字符(即非数字),您可以检查myStream.rdbuf()->in_avail() == 0

这是否与您尝试做的类似?我不确定是否有更好的方法,但我过去做过这件事,对我来说这很好。

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

编辑:我看到你刚刚发布时更新了你的问题。

答案 1 :(得分:8)

一个简单的检查是查看流的字符串内容是否为空:

#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());
}

答案 2 :(得分:5)

一种方法是check the size of the internal string并与零进行比较。请注意,这与AusCBlock建议的myStream.rdbuf()->in_avail()不同; in_avail()可以返回一个与流的实际大小不同的值(例如,如果内部缓冲区用多个非连续的内存块表示)。特别是,in_avail() 原则上可以在非空缓冲区中返回零stringbuf规范可能会进一步限制这一点;我没有检查过那么多细节)。

答案 3 :(得分:4)

此方法很有效,并且也适用于输出字符串:

ostringstream report_string;

if (report_string.tellp() == 0) {
    // do something
}

答案 4 :(得分:3)

改用eof()。

示例代码:

stringstream report_string;
if ( !(report_string.eof()) ) 
    cout << "report_string EMPTY! \n";

答案 5 :(得分:1)

使用它通常是合理且可读的......

report_string.str().empty()

...但这可能涉及动态分配并将整个字符串复制到临时字符串,只是被丢弃。

如果表现很重要,另一个选择是......

report_string.peek() == decltype(report_string)::traits_type::eof()
  • 这会从流中查找 尚未提取 的字符,忽略已经 成功的输入 解析/提取

    • 与测试report_string.str().empty()不同,后者仍然“看到”已经提取的输入
  • 如果之前的解析将流保存为fail状态但未clear(),则无论是否有更多未提取的字符,都会返回eof()

答案 6 :(得分:0)

另一种方法怎么样?

如果将ostringstream设为可选类型,则可以在使用之前检查它是否已分配。

想象一个名为lazy<>的类,在需要时懒惰地构造一个对象,然后我们可以这样做:

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

产生这个输出:

Hello
Hello
oss2 is not used
Goodbye

优点:

  • 未使用时stringstream没有重复构造。

  • 如果随后使用未使用的字符串流(通过const引用),则可选提供异常

下面的完整示例,可自定义构造函数:

我已将std::experimental用于optional,但您可以轻松使用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;
}

答案 7 :(得分:0)

我知道这个问题很老而且已经回答了,但是根据情况,可能还有另一种值得考虑的方法:

在测试字符串流是否为空时,您应该适当地对单个字符串或字符串流中的每一行进行处理;因此,您很可能会在字符串流上使用>>运算符或std::getline……如果流为空,则它们的值仅为false,因此您可以编写:

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
}

应该注意的是,这种方法假定您正在计划在字符串流中循环;如果没有,则无法使用这种方法。