13

Clearly I am missing something important about stringstreams in general here, but could someone explain why

#include <sstream>
using namespace std;

stringstream foo() {
  stringstream ss;
  return ss;
}

Fails with

In file included from /usr/include/c++/4.4/ios:39,
             from /usr/include/c++/4.4/ostream:40,
             from /usr/include/c++/4.4/iostream:40,
             from rwalk.cpp:1:/usr/include/c++/4.4/bits/ios_base.h: In copy constructor ‘std::basic_ios<char,    std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)’:/usr/include/c++/4.4/bits/ios_base.h:790: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private
/usr/include/c++/4.4/iosfwd:47: error: within this context
/usr/include/c++/4.4/iosfwd: In copy constructor ‘std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::basic_stringstream(const std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&)’:
/usr/include/c++/4.4/iosfwd:75: note: synthesized method ‘std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)’ first required here 
/usr/include/c++/4.4/streambuf: In copy constructor ‘std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::basic_stringbuf(const std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >&)’:
/usr/include/c++/4.4/streambuf:770: error: ‘std::basic_streambuf<_CharT, _Traits>::basic_streambuf(const std::basic_streambuf<_CharT, _Traits>&) [with _CharT = char, _Traits = std::char_traits<char>]’ is private
/usr/include/c++/4.4/iosfwd:63: error: within this context
/usr/include/c++/4.4/iosfwd: In copy constructor ‘std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::basic_stringstream(const std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&)’:
/usr/include/c++/4.4/iosfwd:75: note: synthesized method ‘std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::basic_stringbuf(const std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >&)’ first required here 
rwalk.cpp: In function ‘std::stringstream foo()’:
rwalk.cpp:12: note: synthesized method ‘std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::basic_stringstream(const std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >&)’ first required here 

How does one return a stringstream from a function properly? (edit: added the headers for a complete code snippet and fixed typo)

Hooked
  • 84,485
  • 43
  • 192
  • 261

6 Answers6

19

After correct the type-o in the return type (noted by Mahesh), your code will not compile in C++03 because stringstream is not copyable. However if your compiler supports C++0x, turning that on allows your code to compile because stringstream is MoveConstructible.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • I think it cannot compile even in C++11 without `std::move()`. – magras Oct 19 '14 at 15:31
  • @PetrPervukhin: Why? According to 27.8.6 [stringstream.cons], `basic_stringstream` has a valid, accessible move constructor which will be used to move `ss` out of `foo`. Is there some other reason you see that makes the code not valid C++11? – Howard Hinnant Oct 19 '14 at 16:32
  • I can say about C++03, that if there is no copy constructor in class A, you cannot write `A a = A()`, even if compiler can apply copy constructor elision. So I'm not sure that compiler can replace copy construction with move construction in this example. – magras Oct 19 '14 at 20:15
  • Excuse me. I tried it in Coliru, it works fine. So my next question for google and SO will be "why?". =) – magras Oct 19 '14 at 20:29
  • 1
    @PetrPervukhin: See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm#Moving%20from%20local%20values for rationale. – Howard Hinnant Oct 19 '14 at 21:44
12

You can't return a stream from a function by value, because that implies you'd have to copy the stream. C++ streams are not copyable.

wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
  • I may be asking the wrong question - but why can't I copy the stream? – Hooked Feb 25 '11 at 16:52
  • 5
    @Hooked it's not obvious what the semantics of stream copies would be. When you write into one copy, should the write also occur in the other? When you close one stream, should the other close as well? When you change one stream's locale, should the other change as well? In correct programs you shouldn't have the _need_ to copy a stream. – wilhelmtell Feb 25 '11 at 16:58
7

Old question but I believe that the correct way to achieve what you want is to use the stringstream::str method that returns a string object with a copy of the current contents in the stream buffer.

Here is an example with string str() const;.

std::string foo() {
    stringstream ss;
    ss << "add whatever you want to the stream" << 12 << ' ' << 13.4;
    return ss.str();
}

int main() {
    std::cout << foo();
    return 0;
}

which prints:

add whatever you want to the stream 12 13.4 
BugShotGG
  • 5,008
  • 8
  • 47
  • 63
3

While it does not work in C++03, it should work in C++11. However, current compilers may still have problems (due to the lack of full C++11 compatibility), e.g. the above code will not compile in g++ 4.6.1

user1239014
  • 111
  • 3
1

In C++03 you'll have to either pass the stringstream as a parameter by non-const reference or return just the resulting string (ss.str()), as you can't copy the stream.

Mark B
  • 95,107
  • 10
  • 109
  • 188
-2

You have to include sstream and have std::stringstream instead of stringstream.

John Paul
  • 12,196
  • 6
  • 55
  • 75
vmpstr
  • 5,051
  • 2
  • 25
  • 25