Reputation: 2061
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 << "some string here...";
In my code itself are various conditions for assigning values to the report_string variable.
I'd like to check whether it was assigned a value or not.
Upvotes: 65
Views: 97345
Reputation: 1165
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.
Upvotes: 3
Reputation: 18532
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.
Upvotes: 71
Reputation: 1826
This method is efficient and should work with output strings as well:
ostringstream report_string;
if (report_string.tellp() == 0) {
// do something
}
Upvotes: 18
Reputation: 69942
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;
}
Upvotes: 0
Reputation: 106254
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
report_string.str().empty()
, which still "sees" already-extracted inputif 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
Upvotes: 7
Reputation: 83
Use eof() instead.
Sample Code:
stringstream report_string;
if ( !(report_string.eof()) )
cout << "report_string EMPTY! \n";
Upvotes: 5
Reputation: 157
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());
}
Upvotes: 12
Reputation: 231471
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).
Upvotes: 6