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.