【问题标题】:Why are move semantics for a class containing a std::stringstream causing compiler errors?为什么包含 std::stringstream 的类的移动语义会导致编译器错误?
【发布时间】:2012-08-14 11:58:13
【问题描述】:

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

#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

... 并得到一堵关于为 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]

...这持续了好几页。

我的代码有什么问题?

更新 1:Clang 3.0 失败,结果相似。
更新 2:g++ 4.7 也失败。
更新 3 :使用答案作为指导,我发现了这个:c++11 status in libstdc++ - “27.5 Iostreams 基类:在 basic_ios 上缺少移动和交换操作。”诅咒!

【问题讨论】:

    标签: c++ c++11 g++ stringstream move-semantics


    【解决方案1】:

    更新

    需要按照 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++11 确认问题,ubuntu 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>&)’
    

    仍然存在。

    解决方法

    请改用std::unique_ptr&lt;std::stringstream&gt;。最好是用 c++14 自带的make_unique 初始化它,或者以我的博客cpp11style-no-new-delete 为例(这是一个较早的版本,但它可以很好地用于此目的)。

    【讨论】:

    • gcc 错误 54316 已在 gcc 5 中修复。我刚刚用最近的 gcc 5 测试了 OP 的代码,它确实可以编译。
    【解决方案2】:

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

    ~/blargh $ cat t.cpp #include 诠释主要(){ 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++ 在这方面坏了。

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 标准似乎没有 std::ios_basestd::basic_ios 的移动 ctors(不是他们需要它),在 std::basic_(i|o)stream 他们受到保护并且派生类是公共的.
      • @Puppy “顺便说一句,自赋值检查赋值运算符很糟糕。”你能澄清一下吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-23
      • 1970-01-01
      • 2020-04-26
      • 2016-05-13
      • 2019-11-18
      相关资源
      最近更新 更多