std::ostringstream printing the address of the c-string instead of its content
The expressionstd::ostringstream()
creates a temporary, and operator<<
which takes const char*
as argument is a free function, but this free function cannot be called on a temporary, as the type of the first parameter of the function is std::ostream&
which cannot be bound to temporary object.
Having said that, <<std::ostringstream() << "some data"
resolves to a call to a member function which is overloaded for void*
which prints the address. Note that a member function can be invoked on the temporary.
In order to call the free function, you need to convert temporary (which is rvalue) into a lvalue, and here is one trick that you can do:
std::cout << "Inline : "
<< dynamic_cast<std::ostringstream&>(
std::ostringstream().flush() << "some data"
).str()
<< "\n";
That is, std::ostringstream().flush()
returns std::ostream&
which means, now the free function can called, passing the returned reference as first argument.
Also, you don't need to use dynamic_cast
here (which is slow, as it is done at runtime), for the type of the object is pretty much known, and so you can use static_cast
(which is fast as it is done at compile-time):
std::cout << "Inline : "
<< static_cast<std::ostringstream&>(
std::ostringstream().flush() << "some data"
).str()
<< "\n";
which should work just fine.
sending c-string to non-lvalue std::ostringstream weird behaviour
In C++03, the non-member operator<<
(source) which is responsible for printing out C strings, namely
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
cannot accept an rvalue stream, so instead a member overload (inherited from the std::ostream
base class) is chosen (source):
basic_ostream& operator<<( const void* value );
This prints out the address.
In C++11, there is an rvalue stream insertion operator,
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
which ensures that the behaviour will be the same for lvalue and rvalue streams. Note that this overload could not have been written in C++03, as the only way to bind to an rvalue would be through a const lvalue reference.
The first string argument to a stringstream is saved as a pointer/garbage
The problem is indeed that the stream is a temporary.
Before C++11, there was no non-member operator<<
overload that took an rvalue reference as the first parameter (aka, allowing writes to temporary streams).
As such, the only valid operator<<
overloads were the members, since all non-member overloads take a non-const
reference and as such will not bind to temporaries. One of those non-member overloads is the one responsible for printing C strings (aka char const*
). Here's one of the member overloads:
basic_ostream<Ch, Traits>& operator<<(void* p);
And guess what your string literal liberally converts to. :)
After the first string, you get a normal reference back from the call to operator<<
, which will then allow the non-member overloads to be viable.
Console couts a memory address instead of string
When people say that strings are like arrays, they mean specifically "c-strings", which are just char arrays (char*
, or char []
). std::string
is a separate C++ class, and is not like an array. See this question for a definition of C-strings.
In your example, str1 is actually an array of std::strings, and when you print it, you're printing the pointer address.
Below is an example using both C++ std::string
, and a C-string, to illustrate the difference. In general, when writing C++, you should prefer std::string.
const int n = 2;
std::string str1; //A c++ std::string, which is not like an array
char cstr1[n+1]; // a c-string, which is array-like
for(int i = 0; i < n; ++i) {
char input = '\0';
cout<<"enter letter: ";
cin>>input;
str1.push_back(input); //Append to c++ string
cstr1[i] = input; //Add to array-like c-string
}
cstr1[n] = '\0'; //Ensure C-string is null-terminated
cout << "As C++: " << str1 << std::endl;
cout << "AS C: " << cstr1 << std::endl;
cout << "C++ can convert to C-string: " << str1.c_str() << std::endl;
Added const to n, to make it valid C++, since you shouldn't create arrays from non-const variables
Why does calling cout.operator(const char*) print the address instead of the character string?
When you do cout.operator<<(str)
you call cout
's operator <<
member function. If we look at what member functions overloads cout
has we have
basic_ostream& operator<<( short value );
basic_ostream& operator<<( unsigned short value );
basic_ostream& operator<<( int value );
basic_ostream& operator<<( unsigned int value );
basic_ostream& operator<<( long value );
basic_ostream& operator<<( unsigned long value );
basic_ostream& operator<<( long long value );
basic_ostream& operator<<( unsigned long long value );
basic_ostream& operator<<( float value );
basic_ostream& operator<<( double value );
basic_ostream& operator<<( long double value );
basic_ostream& operator<<( bool value );
basic_ostream& operator<<( const void* value );
basic_ostream& operator<<( std::nullptr_t );
basic_ostream& operator<<( std::basic_streambuf<CharT, Traits>* sb);
basic_ostream& operator<<(
std::ios_base& (*func)(std::ios_base&) );
basic_ostream& operator<<(
std::basic_ios<CharT,Traits>& (*func)(std::basic_ios<CharT,Traits>&) );
basic_ostream& operator<<(
std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );
If you notice, there isn't one for a const char*
, but there is one for a const void*
. So, your const char*
is converted to a const void*
and that version of the function prints the address held by the pointer.
What you need to do is call the non member function overload of operator<<
and to do that you can use
cout << str;
Printing a string to a temporary stream object in C++
The overload ostream& operator<< (ostream& out, const char*)
is not viable because your temporary won't bind to the non-const reference ostream&
. There isn't really much you can do about that (since you can't cast an rvalue to an lvalue) other than declaring a local variable and using that:
{
specialstringstream ss;
ss << "Hello world" << std::endl; // OK, can bind to lvalue
}
Possible solution: You could declare another overload that accepts an rvalue reference:
std::ostream & operator<<(specialstringstream && o, const char * s)
{
return o << s; // note: *not* "std::move(o)"
}
Related Topics
For Purposes of Ordering, Is Atomic Read-Modify-Write One Operation or Two
Double Delete in Initializer_List VS 2013
Searching in a Sorted and Rotated Array
Generating a Normal Map from a Height Map
C++ Undefined References with Static Library
Checking for Eof in String::Getline
How to Make a Heterogeneous Boost::Map
Why Are Bitwise Shifts (<< and >>) Used for Cout and Cin
Detecting Usb Insertion/Removal Events in Windows Using C++
How to Avoid Static Member Function When Using Gsl with C++
Why Should I Ever Use Inline Code
Get Absolute Value Without Using Abs Function Nor If Statement
How to Reduce Compile Time, and Linking Time for Visual C++ Projects (Native C++)
What Is a Buffer Overflow and How to Cause One
Refreshing the Auto Complete (Intellisense) Database in Visual Studio