Printing Stringstream Outputs Pointer - c++

Rather than outputting the expected string of "Bar", the following code outputs what looks to be a pointer.
#include <sstream>
#include <iostream>
int main()
{
std::stringstream Foo("Bar");
std::cout << Foo << std::endl; // Outputs "0x22fe80."
return 0;
}
This can be worked around by using Foo.str(), but it's caused some issues for me in the past. What causes this strange behavior? Where is it documented?

This can be worked around by using Foo.str(), but it's caused some issues for me in the past. What causes this strange behavior? Where is it documented?
It's not strange at all.
A stream is a stream, not a string.
You can obtain the [string] buffer with the member function .str(). That's not a workaround: it's the API. It should be documented in your C++ standard library reference, and if it's not then your reference is incomplete/wrong.
(What is slightly strange is that you get a memory address rather than a compilation error; that is due to the use of the safe bool idiom in the pre-C++0x standard library, as covered in another answer.)

A std::stringstream is not supposed to be inserted in a stream. That's why you have the str() method.
The behavior you're observing is due to the fact that std::stringstream has a conversion to void*, which is what is used to test the stream:
if(Foo) { // this uses the conversion to void*
}
In C++11, this conversion is replaced by an explicit conversion to bool, which causes this code not to compile:
std::cout << Foo << std::endl;

(1)use std::cout << Foo << std::endl; you should make sure stringstream has already overload "<<".
(2)if there is not overload "<<" , use std::cout << Foo << std::endl; may output the Foo's address.

Related

Can I use an std::ostream to print into a given buffer?

I have a given buffer of characters (maybe even the buffer backing an std::string, but never mind that). I want to print into that buffer using an std::ostream, i.e. I want to be able to write:
span<char> my_buffer = get_buffer();
auto my_os = /* magic */;
static_assert(
std::is_base_of<std::basic_ostream<char>,decltype(my_os)>::value,
"magic failed");
my_os << "hello" << ',' << 123 << '\0';
std::cout << my_buffer << '\n';
and get:
hello,123
on the standard output.
Note: C++11 if possible, and please mention the language standard you're using. (And yes, I know C++11 doesn't have spans.)
(Thank #BoP and #T.C. for the two parts of this solution)
This can be done... if you're willing to use a deprecated C++ construct: std:ostrstream.
#include <strstream>
#include <iostream>
int main() {
const size_t n = 20;
char my_buffer[n];
std::ostrstream my_os(my_buffer, n);
my_os << "hello" << ',' << 123 << '\0';
std::cout << my_buffer << '\n';
}
Notes about this code:
It works (GodBolt)
It is valid C++98! ... of course I had to let go of std::span, auto type inference etc. It's also valid C++11 and later standards.
This will construct an std::strstreambuf, which is what an std::ostrstream uses directly, from your buffer of chars.
(see this on GodBolt)
Unfortunately, with the deprecation of std::ostrstream, we were left with no fully-valid alternative up to, and including, C++20. You would need to implement a custom std::basic_streambuf, and assign it to an std::ostream. :-(
But in C++23 - you are luck! The standard library does offer exactly what you asked for: std::spanstream: A std::ostream backed by a span of char's which it is given at construction.

Assigning a number to std::string is now allowed?

Consider the following code snippet:
#include <iostream>
int main() {
std::string foo;
foo = -1; // why is the compiler not complaining about this?
std::cout << "1" << std::endl;
std::cout << foo << std::endl;
std::cout << "2" << std::endl;
}
Actual output (both ideone.com C++14 mode and GCC 4.8.4):
<no output>
Questions:
Why did the code snippet compile at all?
Commenting out foo = -1, I get the correct stdout (1 and 2). What has the compiler compiled with foo = -1; that causes the subsequent couts to fail?
foo = -1;
resolves to std::string::operator=(char) since -1 is an int and int can, in theory, be converted to a char.
It's not clear to me what the standard says when the int does not represent a valid char. It looks like in your implementation, the program crashes.
Update
From the C++11 Standard (emphasis mine):
3.9.1 Fundamental types
1 Objects declared as characters (char) shall be large enough to store any member of the implementation’s basic character set. If a character from this set is stored in a character object, the integral value of that character
object is equal to the value of the single character literal form of that character. It is implementation-defined whether a char object can hold negative values.
It appears that you'll have to consult your compiler's documentation to understand whether it allows char object to hold negative values and, if it does, how does it treat such objects.
char is an integral type in C++. std::string defines an assignment operator:
std::string& operator=(char);
Since int converts to char freely in this context, no diagnostic is given. (It's funny how best intentions pave the road to Hell, innit?)
Since (char)-1 is probably not a valid member if the execution character set on your platform, the stream enters an error state and will stay there, outputting nothing, until the error bit is cleared.
EDIT this is a bug of ideone. If the output stream contains an "illegal" character, the entire stream is not shown, even the parts produced and flushed before the bad character. Use another online compiler to check.
These are the operator= overloads for the string class :-
basic_string& operator=(const basic_string& str);
basic_string& operator=(basic_string&& str) noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value);
basic_string& operator=(const charT* s);
basic_string& operator=(charT c);
basic_string& operator=(initializer_list<charT>);
Hope that makes sense why that compiled fine.
Now coming onto your question as to why there is no output. I have tweaked the code a little :-
#include <iostream>
int main() {
std::string foo;
foo = -1; // why is the compiler not complaining about this?
char ch = 65;
std::cout << "1" << std::endl;
std::cout << foo << std::endl;
std::cout << ch << std::endl;
//change ch to -1 ... ascii
ch = -1;
std::cout << ch << std::endl;
std::cout << "2" << std::endl;
}
Can you guess what the output is ? Yup think in terms of ascii :-
1
 
A
 
2
That's exactly the reason why you don't have the output for -1.
Compiler - MinGW - std=c++14 -- not sure why IDEONE messes up the complete output stream in your case.

Why does stream insertion of an empty streambuf fail?

I was using the simple file-slurp and I decided to add some error checking. I was surprised that an empty file gives an error. This doesn't happen with every empty sequence either, "" works fine. I also verified that rdbuf() is returning a non-null pointer.
#include <iostream>
#include <sstream>
using namespace std;
int main(int, char**){
istringstream in(""); // Succeeds if non-empty
stringstream sstr;
if (sstr << in.rdbuf()) { // Succeeds if I replace in.rdbuf() with ""
cout << "Read Successful\n";
}else{
cout << "Read Failed\n";
}
}
It sets failbit because the standard requires it. (I feel foolish now. I thought I might have been doing something wrong.) Section 27.7.3.6.3.9 of the November 2014 Draft says:
If the function inserts no characters, it calls setstate(failbit) (which may throw ios_base::failure (27.5.5.4)).
Why the committee decided to make this behavior different from other sequence insertions (like char* and string) which do not consider insertion of nothing to be a failure is still a mystery. But I now know it is not a failure indicating misuse of the object.

Is streaming a stringstream a libstdc++ extension?

Is streaming a stringstream a libstdc++ extension? This program compiles with gcc-4.2, gcc-4.7-2 (using -std=c++03), and clang 3.2 using -std=c++11 and libstdc++ (thanks to Andy Prowl, see comments). It does not compile with clang 3.2 using -std=c++11 and -stdlib=libc++.
#include<iostream>
#include<sstream>
int main() {
std::stringstream s; s << "b";
std::cout << "ss: " << s << std::endl;
return 0;
}
By looking at the constructor of ofstream it can take a std::basic_streambuf<CharT, Traits>* or a basic_ostream& st. A stringstream is a std::basic_istream, however both are std::basic_ios<CharT, Traits> so I would guess it should work.
The following change makes the code compile under clang:
std::cout << "ss: " << s.str() << std::endl;
What is the right way to do it? cout << s; or cout << s.str(); ?
No, it's a difference between C++03 and C++11. All streams have a conversion operator that enables code using if (s) and while (s). In C++03 this is usually operator void*() or something similar.
In C++11 we have explicit operators, where an explicit operator bool() works for if (s), but not for cout << s.
Actually that would compile only in C++98 and C++03, because all stream classes implicity convert into void* due to the presence of operator void*() conversion function, thus s in std::cout << s would convert into void* implicitly.
In C++11, however, the code will not compile because C++11 has made the explicit, which can contextually convert into boolean value, not void*, such as in if and while.
It should compile with all C++ compilers, but it doesn't do what
you might expect. All streams have an implicit conversion to
something which can be used in a boolean expression: either to
void* or bool. And there is a << operator for both of
these types.
When you want to dump one stream into another, the correct way
would be:
std::cout << s.rdbuf();
(It seems a bit strange to me that this is overloaded as
a formatting insertion operator, since it copies the entire
contents of the streambuf, without any formatting, even
ignoring the width.)
there is not overload for streaming std::stringstream, but you can use
std::cout << "ss: " << s.str() << std::endl;

Odd(?) behaviour of a temporary std::ostringstream

I was messing around with std::ostringstream whilst looking at this question: sprintf in c++?, and noticed the stringbuilder() wrapper by Nawaz and thought, well that ought to work with std::ostringstream.
So my first attempt was the following:
std::cout << (std::ostringstream("select * from foo limit") << max_limit).str() << std::endl;
Now this obviously fails to compile (correctly) as the result of the operator<< is a std::ostream - which doesn't have the member str(). So I thought a cast should do the trick, and specifically a cast to a const reference (works with a cast to a normal reference too), so second attempt:
std::cout << static_cast<std::ostringstream const&>(std::ostringstream("select * from foo limit") << max_limit).str() << std::endl;
Now this compiles fine and runs, however the output is, well, not what I was expecting.
10lect * from foo limit
Now - here's the question, am I invoking some undefined behaviour somewhere - and if so where? And how is this different to the approach that Nawaz has taken (I guess aside from the result of his operator is the stringbuilder itself rather than std::ostream).
EDIT: here is the ideone code.
EDIT: oops - forgot to specify, max_limit is int.
You need to move the stream's position to the end of the internal buffer used by ostringstream:
std::ostringstream out("select * from foo limit ", std::ios_base::app);
out << max_limit;
std::cout << out.str () << std::endl;
See the documentation on ostringstream constructor.
What's maxLimit?
Some of the ostream operator<< overloads are free functions, like:
ostream& operator<<(ostream& os, T const&);
If the stream is a temporary (which in your case it is), it cannot bind to that ref-to-non-const, and the overload cannot be chosen.
So you may be using a non-preferred overload by accident; possibly something like the overload for char const*. Hard to tell without knowing what maxLimit is.
This is a limitation when trying to do this serialisation on a single line, and you can't get around it.
You're also attempting to stream std::cout to std::cout, which is obviously not what you intended to do.
Update Vijay figured it out.
std::cout << static_cast<std::ostringstream const&>(
std::ostringstream("select * from foo limit", std::ios_base::app) << max_limit
).str() << std::endl
The above is still definitely worth bearing in mind, though.
You could also simply use flush as:
static_cast<std::ostringstream const&>(std::ostringstream().flush() << "select * from foo limit " << max_limit).str() << std::endl;
But then the code is not same. Its using default constructor.
As a sidenote : isn't dynamic_cast more appropriate here?
Demo : http://www.ideone.com/06xNS