I am trying to make a struct
, in which one of the members is of std::stringstream
type. I am using C++11, and according to http://www.cplusplus.com/reference/sstream/stringstream/operator=/ I can do it.
Here is my code:
struct logline_t
{
stringstream logString; /*!< String line to be saved to a file (and printed to cout). */
ElogLevel logLevel; /*!< The \ref ElogLevel of this line. */
timeval currentTime; /*!< time stamp of current log line */
logline_t& operator =(const logline_t& a)
{
logString = a.logString;
logLevel = a.logLevel;
currentTime = a.currentTime;
return *this;
}
};
It doesn't compile, as I am getting this error:
error: use of deleted function ‘std::basic_stringstream<char>& std::basic_stringstream<char>::operator=(const std::basic_stringstream<char>&)’
I don't understand why it doesn't work. I have tried logString = move(a.logString);
as well. Same result. I would appreciate all help.
Edit: Here is my code, I have applied the changes suggested by most of the users and in my code they do not compile. I am still getting an error at the very beginning of the struct
.
CLogger.h
Line 40: ../src/CLogger.h:40:9: error: use of deleted function ‘std::basic_stringstream<char>::basic_stringstream(const std::basic_stringstream<char>&)’
CLogger.cpp
Line 86: ../src/CLogger.cpp:86:41: error: use of deleted function ‘CLogger::logline_t::logline_t(const CLogger::logline_t&)’
Line 91: ../src/CLogger.cpp:91:9: error: use of deleted function ‘CLogger::logline_t::logline_t(const CLogger::logline_t&)’
If any other information is needed i will provide it.
The StringStream class in C++ is derived from the iostream class. Similar to other stream-based classes, StringStream in C++ allows performing insertion, extraction, and other operations. It is commonly used in parsing inputs and converting strings to numbers, and vice-versa.
To use stringstream class in the C++ program, we have to use the header <sstream>. For Example, the code to extract an integer from the string would be: string mystr(“2019”); int myInt; stringstream (mystr)>>myInt; Here we declare a string object with value “2019” and an int object “myInt”.
To use stringstream, we need to include sstream header file.
std::stringstream
is not copyable. To copy the content you can just write the content of one stream to another:
logString << a.logString.str();
Update:
Also if you don't follow a good advice to implement operator=
with copy-and-swap idiom using copy constructor, you have to clear the stream first:
logString.str({});
logString << a.logString.str();
or just
logString.str(a.logString.str());
Also you may be tempted to use rdbuf()
instead:
logString << a.logString.rdbuf();
but this is incorrect, because it alters the state of a.logString
(despite that a.logString
is const
, a.logString.rdbuf()
is a pointer to non-const object). This is demonstrated by the following code:
logline_t l1;
l1.logString << "hello";
logline_t l2, l3;
l2 = l1;
l1.logString << "world";
l3 = l1;
// incorrectly outputs: l2: hello, l3: world
// correct output is: l2: hello, l3: helloworld
std::cout << "l2: " << l2.logString.str() << ", l3: " << l3.logString.str() << std::endl;
Streams are not copyable. But they are movable.
Still you could make your copy assignment operator work by just creating a suitable stringstream
.
On the third hand it doesn't quite feel right to have a stream as a member? And if you really want that, why not use an ostringstream
, why a stringstream
? By reflecting on this, the design might be improved (and possibly that will the remove the current problem).
Example of workaround by creating a suitable stringstream
(well, ostringstream
), using the exception safe copy/swap idiom:
#include <sstream>
#include <utility> // std::swap
namespace my {
using std::ostringstream;
using std::swap;
struct S
{
ostringstream line;
void swap_with( S& other ) noexcept
{
swap( line, other.line );
}
auto operator=( S const& other )
-> S&
{
S temp( other );
swap_with( temp );
return *this;
}
S() = default;
S( S const& other )
: line( other.line.str() )
{}
};
} // namespace my
auto main() -> int
{
my::S o1, o2;
o1 = o2;
}
Note that this relies on std::swap
, which is specialized for ostringstream
.
Example of a simpler but in principle not exception safe workaround:
#include <sstream>
#include <utility> // std::swap
namespace my {
using std::ostringstream;
using std::swap;
struct S
{
ostringstream line;
auto operator=( S const& other )
-> S&
{
line.str( other.line.str() ); // This can in theory throw, but.
return *this;
}
S() = default;
S( S const& other )
: line( other.line.str() )
{}
};
} // namespace my
auto main() -> int
{
my::S o1, o2;
o1 = o2;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With