24

我怎样才能使这个简单的类可移动?我认为是正确的只会产生一堵错误的墙......

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

编译:

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

...并获得有关为字符串流的各种基类调用的复制分配的错误墙。

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]

...这持续了好几页。

我的代码有什么问题?

更新 1:Clang 3.0 失败,结果相似。
更新 2:g++ 4.7 也失败了。
更新 3:使用答案作为指导,我发现:c++11 status in libstdc++ - “27.5 Iostreams base classes: Missing move and swap operations on basic_ios。” 诅咒!

4

3 回答 3

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;

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

basic_stringstream(basic_stringstream&& rhs);

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

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

阅读包含文件include/std/sstream我发现没有移动构造函数或任何提及 C++0x 或 C++11。(比较std::string哪个确实有效。)

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

basic_stringstream(basic_stringstream&& rhs){}

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

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

遗迹。

解决方法

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

于 2012-08-18T11:58:06.410 回答
5

Clang 3.0 是 C++98,Clang 3.1 编译得很好(使用 libc++):

~/blargh $ cat t.cpp
#include <sstream>

诠释主要(){
  auto get_s = []{ return std::stringstream("hi"); };
  汽车 s ​​= get_s();
}
~/blargh $ 铿锵声 -v
clang 3.1 版(主干 152621)
目标:x86_64-unknown-linux-gnu
线程模型:posix
~/blargh $ clang++ -std=c++0x -stdlib=libc++ -Wall -pedantic t.cpp
〜/大声$

您的示例也可以很好地完成,所以我猜是 libstdc++ 在这方面被破坏了。

于 2012-08-18T09:35:08.903 回答
2

您可能使用了错误版本的库。您的代码没有理由无效。

顺便说一句,自赋值检查赋值运算符很糟糕。

编辑:奇怪的是,Visual Studio 似乎也相信basic_stringstream没有移动构造函数。所有流在 C++11 中都应该是可移动的。也许这是一个标准缺陷,或者实现移动构造函数需要 C++11 功能,但尚不支持。从概念上讲,它没有理由失败,但我实际上找不到任何支持它的东西。

于 2012-08-18T04:41:44.673 回答