簡體   English   中英

如何檢查StringStream變量是否為空/ null?

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

這里只是一個簡單的問題。 到目前為止,我一直在尋找無濟於事。

這里有更多信息:

stringstream report_string;

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

在我的代碼中,有各種條件為report_string變量賦值。

我想檢查它是否被賦值。

myStream.rdbuf()->in_avail()可以用來獲取可用字符准備從讀出的數stringstream ,你可以用它來檢查,如果你的stringstream是“空”。 我假設你實際上並沒有嘗試檢查null

例如,如果你想提取的intstringstream ,然后看看是否有任何遺留下來的字符,你可以檢查(即非數字)。 myStream.rdbuf()->in_avail() == 0

這與你想做的事情類似嗎? 我不確定是否有更好的方法,但我在過去做過這個,這對我來說很好。

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

編輯:我看到你剛剛發布時更新了你的問題。

一個簡單的檢查是查看流的字符串內容是否為空:

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

此方法很有效,也應該與輸出字符串一起使用:

ostringstream report_string;

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

一種方法是檢查內部字符串的大小並與零進行比較。 請注意,這與myStream.rdbuf()->in_avail()正如AusCBlock建議的那樣; in_avail()可以返回一個與流的實際大小不同的值(例如,如果內部緩沖區用多個非連續的內存塊表示)。 特別是, in_avail() 可以,原則上,在非空緩沖區返回零 (也有可能是stringbuf規范進一步限制這一點;在很多細節我都沒有選中)。

請改用eof()。

示例代碼:

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

這通常是合理的,可讀的......

report_string.str().empty()

...但這可能涉及動態分配並將整個字符串復制到臨時字符串,只能被丟棄。

如果表現很重要,另一種選擇是......

report_string.peek() == decltype(report_string)::traits_type::eof()
  • 這會查找尚未從流中提取的字符,忽略已成功解析/提取的輸入

    • 這與測試report_string.str().empty() ,后者仍然“看到”已經提取的輸入
  • 如果之前的解析使流處於fail狀態,你沒有clear() ed,這將返回eof()無論是否有更多未提取的字符

另一種方法怎么樣?

如果將ostringstream設置為可選類型,則可以在使用之前檢查它是否已分配給它。

想象一個名為lazy<>的類,它在需要時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;
}

我知道這個問題已經很久了,已經回答了,但根據情況,可能還有另一種值得考慮的方法:

當您測試字符串流是否為空時,您正確地打算對字符串流中的各個字符串或每一行執行某些操作; 因此,您很可能在stringstream上使用>>運算符或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
}

應該注意的是,這種方法假設您計划在字符串流中循環; 如果你不是,那么這種方法就無法使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM