8

私の問題を示すために、コンパイルされない次の単純なプログラムを考えてみましょう。

#include <boost/noncopyable.hpp>
#include <unordered_map>

class foo : boost::noncopyable { };

int main()
{
    std::unordered_map<int, foo> m;
    auto & element = m[0];

    return 0;
}

現在のバージョンのブースト (1.52) を使用すると、Visual Studio 2012 は次のエラーを返します: cannot access private member declared in class 'boost::noncopyable_::noncopyable.

std::unordered_map の演算子 [] は、指定されたキーにある要素への参照を返します。これは一見うまくいくように見えます。要素のコピーではなく、要素への参照を要求しました。

この問題についての私の理解は次のとおりです (しばらく C++ を使用していないため、これは間違っている可能性があります)。キーが見つからない場合、unordered_map は新しい要素を作成し、新しい要素への参照を返します。boost::noncopyable は (プライベート) コピー コンストラクターを定義しますが、移動コンストラクターは定義しないため、移動コンストラクターはコンパイラによって生成されません。その operator[] では、std::unordered_map は std::move を使用しますが、boost::noncopyable は移動コンストラクターを定義していないため、コピー コンストラクターにフォールバックします。コピー コンストラクターはプライベートであるため、コンパイルは失敗します。

この投稿を促したのは、boost::noncopyable を継承する boost::signal2::signal の unordered_map を作成しようとしているからです。ブースト ライブラリをハッキングする以外に、簡単な回避策はありますか? 信号を unique_ptr にラップすることはオプションですが、ここで何か間違ったことをしている可能性があります。

アップデート:

投稿が早すぎたかも!boost::noncopyable のサブクラスを unordered_map に追加することは不可能のようです。Insert、operator[]、および emplace はすべて、コピー コンストラクター (非公開) または移動操作 (boost::noncopyable には存在しません) のいずれかを使用します。私には、これが大きな制限のように思えます。boost::noncopyable オブジェクトを含む unordered_map を作成することさえ可能ですか? 私は明示的にそれらをコピーしようとしているわけではありません- unordered_map 内で全寿命を過ごすようにしたいのです。

4

2 に答える 2

7

で のサブクラスを使用することは不可能ではありませboost::noncopyableunordered_map。型の移動コンストラクタを定義するだけです。独自のコピー コンストラクトを作成した場合、C++ はデフォルトのムーブ コンストラクターを作成しません (実際に作成されますboost::noncopyable)。また、デフォルトのムーブ コンストラクターを定義した場合、プライベートな親のコピー コンストラクターを呼び出そうとします。boost::noncopyableしたがって、のコピー コンストラクターを呼び出さない移動コンストラクターを定義する必要があります。たとえば、これはうまくいきます:

#include <boost/noncopyable.hpp>
#include <unordered_map>

struct foo : public boost::noncopyable
{
    foo() = default;
    foo(foo&&) {}
};

int main()
{
    std::unordered_map<int, foo> m;
    auto & element = m[0];

    return 0;
}
于 2012-12-22T09:36:33.580 に答える
1

これはおそらくあなたが探しているものとはまったく異なりますが、私はそれをそこに投げたいと思いました. 注意すべきことの 1 つは、secondから返されたペアの値ですemplace()。これは、2 番目の呼び出しが新しいメンバーを導入したり、既存のメンバーをコピーしたりしないことを示します。

繰り返しますが、これがあなたが望むものに近いかどうかはわかりませんが、試してみる価値はあります. 私は C++11 標準ライブラリにあまり詳しくないので、何か間違ったことをした可能性があります。もしそうならごめんなさい。

最後に、これは挿入+アクセスに使用するというOPの要求に対処しようとしているわけではないことに注意してください。operator []()むしろ、単にboost::noncopyable派生物を に構築しようとしunordered_map<>ます。find()アクセスするには、タグが最初に存在するかどうかを判断するために、以下の組み合わせとイニシャルが必要になる可能性があります。

ともかく...

#include <boost/noncopyable.hpp>
#include <iostream>
#include <unordered_map>

class Foo : public boost::noncopyable
{
public:
    Foo(int value) : value(value) {};

    void setValue(int value) { this->value = value; }
    int getValue() const { return value; }

private:
    int value;
};


int main(int argc, char *argv[])
{
    typedef std::unordered_map<std::string, Foo> MyMap;
    MyMap mymap;

    // throw ("test".1) into the map
    auto p = mymap.emplace("test", 1);
    auto q = mymap.emplace("test", 2); // should not overwrite the first.

    // dump content
    cout << p.first->second.getValue() << '(' << p.second << ')' << ' '
         << q.first->second.getValue() << '(' << q.second << ')' << endl;

    // modify through the second returned iterator/bool pair.
    q.first->second.setValue(3);

    // dump again, see if p was also updated.
    cout << p.first->second.getValue() << '(' << p.second << ')' << ' '
         << q.first->second.getValue() << '(' << q.second << ')' << endl;

    return 0;
}

出力

1(1) 1(0)
3(1) 3(0)
于 2012-12-22T10:02:10.253 に答える