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++11、ubuntu12.04で問題を確認できます。

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

インクルードファイルを読んで、include/std/sstreammoveコンストラクターや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<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 <ストリーム>

intメイン(){
  auto get_s = []{ return std::stringstream("hi"); };
  auto s = get_s();
}
~/blargh $ clang -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

ライブラリの不良バージョンを使用している可能性があります。コードが無効になる理由はありません。

ちなみに、自己代入チェックの代入演算子は悪いです。

編集:不思議なことに、VisualStudioもbasic_stringstreammoveコンストラクターがないと信じているようです。すべてのストリームはC++11で移動可能である必要があります。おそらくこれは標準の欠陥であるか、moveコンストラクターを実装するにはC++11機能が必要です。どちらもまだサポートされていません。概念的には失敗する理由はありませんが、それをサポートするものは実際には見つかりません。

于 2012-08-18T04:41:44.673 に答える