2016-12-01 4 views
2

私は今日、いくつかのクラスを使用するために必要があってはならないセマンティクス移動++:cが伝えられるところで、この基本設計に続く利益

class Task { 
public: 
    Task() { 
     Handler::instance().add(this); 
    } 
    virtual void doSomething() = 0; 
}; 

class Handler { 
    std::vector<Task*> vec; 
    //yea yea, we are locking the option to use default constructor etc 
public: 
    static Handler& instance() { 
     static Handler handler; 
     return handler; 
    } 

    void add(Task* task) { 
     vec.push_back(task); 
    } 

    void handle() { 
     for (auto t : vec) { 
      t->doSomething(); 
     } 
    } 
}; 

template <class T, int SIZE> 
class MyTask : public Task { 
    T data[SIZE]; 
public: 
    virtual void doSomething() { 
     // actually do something 
    } 
}; 
//somewhere in the code: 
Handler::instance().handle(); 

を、私のクラスは道

class A { 
    MyTask<bool, 128> myTask; 
public: 
    A(int i) {} 
}; 

のようなものです私はAのインスタンスが値であるマップを持っていたいと思っていました

static std::map<int, A> map = { 
    {42, A(1948)}, 
    {88, A(-17)} 
}; 

最初に何かを明確にする - このコードnリアルタイム組み込みシステム上で動作するようになりました。私はいくつかの遺産の理由から新しいメモリを割り当てることはできません。

私の問題は、マップ内の実際のオブジェクトは、私が明示的に作成したものではありませんでしたので、彼らは(私はハンドラの利益を取得していない::コールを処理)Handlerクラスに登録していなかったということでした。

私は、最初の例のマップでは、これらのオブジェクトにのみポイントの配列を作成するような醜い何かをすることなく、これを解決するための良い方法を考え出すてみました。

私が前に移動セマンティクスを使用されることはありませんが、私はそれらについて少し読んで、彼らは私の解決策になることができます思っています。しかし、this answer(最初の例では具体的に)を読んだ後、私は実際には移動セマンティクスを使用することで何の利益も得られないように思えました。

私は(...なぜ一体ませんだって)とにかくそれを試してみましたが、代わりにこのようなものでした。今、私の驚きのためにMyTaskにのコピーコンストラクタはまだ(私はそれで印刷を置くと呼ばれていました

static std::map<int, A> map = { 
    {42, std::move(A(1948))}, 
    {88, std::move(A(-17))} 
}; 

を検証するため)、何らかの理由でハンドラの登録がうまくいっていて、私のインスタンスがdoSomething()呼び出しを楽しんでいました。

私は:: STDについてもっと徹底的に読んで正確にそこに何が起こったのかを理解するための動きを試してみましたが、答えを見つけることができませんでした。

誰でも説明できますか? std :: moveはポインタをどうにかして動かすのですか?または多分それだけで登録が正しく何とか発生する原因と移動しようとしてやる

感謝する本当何もがなかった

編集

はさらに私が求めているものを明確にする:

私はstd :: moveの使用がそこで行われていることに貢献していないことを理解しています。

しかし、いくつかの理由でそれがdoSomethingのを取得するにはマップで私のオブジェクトを取得しましたが()ハンドラを介して呼び出します。それはおそらく別の質問に属しているように私には、サイドノートにその理由

を探しています - 二回、各オブジェクトを作成するオーバーヘッドなしでマップをこのように初期化するためのまともな方法は何ですか?

+1

この質問はまだ私には分かりません。あなたの例は実際には意味をなさない - この 'std :: map'はどこから始まり、' Handler'にはどういう関係がありますか?実際の[mcve] – AndyG

+0

を作成して、地図の再生場所が問題になるのはなぜですか?ハンドラは作成されたTaskオブジェクトを登録します – user2717954

+0

:メモリ割り当てを許可されていない場合、おそらく 'std :: map'を使用することは許されません(ただし、あなたの制約に違反する)。 – Hurkyl

答えて

1

あなたの質問は、それが必要とするよりも、その中の多くのがありますが、私はここに根質問を理解だと思います。std::mapコンストラクタはinitialization_listを受け取るので、(5) from this listを呼び出しています。 initializer_listのコピーが基になるオブジェクトをコピーしないため、オブジェクトは移動されずに反復処理されるときにinitializer_listからコピーされます。同じことが他のstdコンテナにも影響します。ここにはvectorの例があります。 (live link)

#include <vector> 
#include <iostream> 

struct Printer { 
    Printer() { std::cout << "default ctor\n"; } 
    Printer(const Printer&) { std::cout << "copy\n"; } 
    Printer(Printer&&) { std::cout << "move\n"; } 
}; 

int main() { 
    std::vector<Printer> v = {Printer{}}; 
} 

あなたが{std::move(Printer{})}を使用する場合は、コンパイラが簡単に離れて最適化を得ることができないというミックスに別の動きを追加します。

+0

私はこれを理解していますが、実際の問題はなぜそれが実際に私の問題を解決したのですか? – user2717954

+0

あなたの問題が 'new'を使うことができないなら、それはしませんでした。地図は新しいものを使用する –

+0

私は地図を使うことができます(確かに、馬鹿だとは思いますが、これは私の会社のルールです) – user2717954

関連する問題