How can I make this simple class movable? What I thought was correct just produces a wall of errors...
#include <iostream> #include <sstream> #include <utility> class message { public: message() = default; // Move constructor message( message &&other ) : stream_( std::move( other.stream_ ) ) // Nope {} // Move assignment message &operator=( message &&other ) { if ( this != &other ) { stream_ = std::move( other.stream_ ); // Nope #2 } return *this; } private: message( const message & ) = delete; message &operator=( const message & ) = delete; std::stringstream stream_; // Other member variables omitted }; int main() { message m; return 0; }
Compile:
$ g++ --version g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 $ g++ -Wall -Wextra -std=c++0x move.cpp -o move
... and get a wall of errors about the copy assignments being called for various base classes of the stringstream.
move.cpp: In constructor ‘message::message(message&&)’: move.cpp:12:40: error: use of deleted function ‘std::basic_stringstream<char>::basic_stringstream(const std::basic_stringstream<char>&)’ In file included from move.cpp:2:0: /usr/include/c++/4.6/sstream:483:11: error: ‘std::basic_stringstream<char>::basic_stringstream(const std::basic_stringstream<char>&)’ is implicitly deleted because the default definition would be ill-formed: /usr/include/c++/4.6/sstream:483:11: error: use of deleted function ‘std::basic_iostream<char>::basic_iostream(const std::basic_iostream<char>&)’ In file included from /usr/include/c++/4.6/iostream:41:0, from move.cpp:1: /usr/include/c++/4.6/istream:774:11: error: ‘std::basic_iostream<char>::basic_iostream(const std::basic_iostream<char>&)’ is implicitly deleted because the default definition would be ill-formed: /usr/include/c++/4.6/istream:774:11: error: use of deleted function ‘std::basic_istream<char>::basic_istream(const std::basic_istream<char>&)’ /usr/include/c++/4.6/istream:57:11: error: ‘std::basic_istream<char>::basic_istream(const std::basic_istream<char>&)’ is implicitly deleted because the default definition would be ill-formed: /usr/include/c++/4.6/istream:57:11: error: use of deleted function ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’ [SNIP]
... This goes on for several pages.
What's wrong with my code?
Update 1: Clang 3.0 fails with similar results.
Update 2: g++ 4.7 fails also.
Update 3: Using the answers as a guide, I found this: c++11 status in libstdc++ - "27.5 Iostreams base classes: Missing move and swap operations on basic_ios." Curses!
std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
Move semantics allows you to avoid unnecessary copies when working with temporary objects that are about to evaporate, and whose resources can safely be taken from that temporary object and used by another.
std::move is totally unnecessary when returning from a function, and really gets into the realm of you -- the programmer -- trying to babysit things that you should leave to the compiler.
"std::move" should only be used where moving can happenWhen passing the result of std::move as a const reference argument. In this case, no object will be moved since it's impossible to call the move constructor from within the function.
It is required to work according to the C++11/14 standards. GCC 5.0 gets it right, and the below mentioned bug is RESOLVED. Thank you GCC team!
It's a missing feature in gcc (or as Xeo points out libstdc++) as of yet.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
According to the standard,
typedef basic_stringstream<char> stringstream;
and from 27.8.5, there is a public move constructor
basic_stringstream(basic_stringstream&& rhs);
I can confirm the problem with gcc 4.7 -std=c++11
, ubuntu 12.04.
std::stringstream a; std::stringstream b=std::move(a);
reading the include file include/std/sstream
I find no move constructor or any mentioning of C++0x or C++11. (compare with std::string
which does work.)
Adding a (mock) move constructor:
basic_stringstream(basic_stringstream&& rhs){}
reduces the error to only tree lines, but
use of deleted function ‘std::basic_stringstream<char>::basic_stringstream( const std::basic_stringstream<char>&)’
remains.
Use a std::unique_ptr<std::stringstream>
instead. Best is to initialize it with make_unique
which comes with c++14, or take it for example from my blog cpp11style-no-new-delete (that is an earlier version, but it will work fine for this purpose).
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