为什么移动包含std :: stringstream的类的语义会导致编译器错误?

x-x*_*x-x 24 c++ g++ stringstream move-semantics c++11

如何让这个简单的类移动?我认为是正确的只会产生一堵错误之墙......

#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;
}
Run Code Online (Sandbox Code Playgroud)

编译:

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

...并为字符串流的各种基类调用复制分配错误.

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]
Run Code Online (Sandbox Code Playgroud)

......这可以持续几页.

我的代码出了什么问题?

更新1:Clang 3.0失败,结果相似.
更新2:g ++ 4.7也失败了.
更新3:使用答案作为指导,我发现:libstdc ++中的c ++ 11状态 - "27.5 Iostreams基类:缺少basic_ios上的移动和交换操作." 诅咒!

Joh*_*erg 26

更新

它需要按照C++ 11/14标准工作.GCC 5.0正确,下面提到的错误已被解决.谢谢GCC团队!

原始答案

它是gcc中缺少的一个功能(或者Xeo指出libstdc ++).

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

根据标准,

typedef basic_stringstream<char> stringstream;
Run Code Online (Sandbox Code Playgroud)

从27.8.5开始,有一个公共移动构造函数

basic_stringstream(basic_stringstream&& rhs);
Run Code Online (Sandbox Code Playgroud)

我可以用gcc 4.7 -std=c++11ubuntu 12.04 确认问题.

std::stringstream a;
std::stringstream b=std::move(a);
Run Code Online (Sandbox Code Playgroud)

阅读包含文件include/std/sstream我发现没有移动构造函数或任何提及C++ 0x或C++ 11.(与std::string哪个相比起作用.)

添加(模拟)移动构造函数:

basic_stringstream(basic_stringstream&& rhs){}
Run Code Online (Sandbox Code Playgroud)

将错误减少到只有树线,但是

use of deleted function ‘std::basic_stringstream<char>::basic_stringstream(
   const std::basic_stringstream<char>&)’
Run Code Online (Sandbox Code Playgroud)

遗迹.

解决方法

std::unique_ptr<std::stringstream>改用.最好make_unique用c ++ 14 来初始化它,或者从我的博客cpp11style-no-new-delete(这是早期版本,但它可以正常工作)中获取它.

  • gcc bug 54316已在gcc 5中修复.我刚用最近的gcc 5测试了OP的代码,它确实编译了. (3认同)

Xeo*_*Xeo 5

Clang 3.0是C++ 98,Clang 3.1编译得很好(用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 $

你的例子也很好,所以我猜它的libstdc ++在这方面已经破了.