library example c++ c++11 g++ stringstream move-semantics

c++ - example - ¿Por qué las semánticas de movimiento para una clase que contiene un std:: stringstream causan errores en el compilador?



stringstream library include (3)

¿Cómo puedo hacer esta clase simple movible? Lo que pensé que era correcto solo produce una pared de errores ...

#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; }

Compilar:

$ g++ --version g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 $ g++ -Wall -Wextra -std=c++0x move.cpp -o move

... y obtenga una gran cantidad de errores sobre las asignaciones de copia que se están llamando para varias clases base de la cadena de cadenas.

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]

... Esto continúa por varias páginas.

¿Qué pasa con mi código?

Actualización 1 : Clang 3.0 falla con resultados similares.
Actualización 2 : g ++ 4.7 también falla.
Actualización 3 : Usando las respuestas como guía, encontré esto: c ++ 11 status en libstdc ++ - "27.5 Clases base de Iostreams: Faltan operaciones de movimiento e intercambio en basic_ios". Maldiciones


Actualizar

Se requiere trabajar de acuerdo con los estándares C ++ 11/14. GCC 5.0 lo hace bien, y el error mencionado abajo está RESUELTO. Gracias equipo de GCC!

Respuesta original

Es una característica que falta en gcc (o como Xeo señala libstdc ++) hasta el momento.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316

Según la norma,

typedef basic_stringstream<char> stringstream;

y desde 27.8.5, hay un constructor de movimiento público.

basic_stringstream(basic_stringstream&& rhs);

Puedo confirmar el problema con gcc 4.7 -std=c++11 , ubuntu 12.04.

std::stringstream a; std::stringstream b=std::move(a);

leyendo el archivo de include/std/sstream no encuentro ningún constructor de movimientos ni ninguna mención de C ++ 0x o C ++ 11. (compare con std::string que funciona.)

Añadiendo un constructor de movimiento (simulado):

basic_stringstream(basic_stringstream&& rhs){}

reduce el error a solo arboles, pero

use of deleted function ‘std::basic_stringstream<char>::basic_stringstream( const std::basic_stringstream<char>&)’

permanece.

Solución

Use un std::unique_ptr<std::stringstream> lugar. Lo mejor es make_unique con make_unique que viene con c ++ 14, o tomarlo, por ejemplo, de mi blog cpp11style-no-new-delete (es una versión anterior, pero funcionará bien para este propósito).


Clang 3.0 es C ++ 98, Clang 3.1 compila esto bien (con libc ++):

~/blargh $ cat t.cpp #include <sstream> int main(){ auto get_s = []{ return std::stringstream("hi"); }; auto s = get_s(); } ~/blargh $ clang -v clang version 3.1 (trunk 152621) Target: x86_64-unknown-linux-gnu Thread model: posix ~/blargh $ clang++ -std=c++0x -stdlib=libc++ -Wall -pedantic t.cpp ~/blargh $

Tu ejemplo cumple muy bien también, así que supongo que es libstdc ++ que está roto en ese sentido.


Es probable que estés usando una versión mala de la biblioteca. No hay ninguna razón por la que su código no sea válido.

Por cierto, los operadores de asignación de comprobación de autoasignación son malos.

Edición: Curiosamente, Visual Studio también parece creer que basic_stringstream no tiene constructor de movimientos. Todas las corrientes deben ser móviles en C ++ 11. Quizás este es un defecto estándar, o la implementación del constructor de movimiento requiere una característica de C ++ 11 que aún no es compatible. Conceptualmente, no hay razón para que falle, pero realmente no puedo encontrar nada que lo respalde.