2016-12-01 52 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 eeds在實時嵌入式系統上運行,所以我不能使用新的內存來分配內存以滿足多種原因。

我的問題是,地圖中的實際對象不是我明確創建的,所以它們沒有在Handler類中註冊(所以我沒有得到Handler :: handle調用的好處) 。

我試圖找到一個很好的方法來解決這個問題,而不需要做一些醜陋的事情,比如先創建一個A數組,然後只指向地圖中的這些對象。

我從來沒有使用過移動語義,但我已經讀了一點關於他們,並認爲他們可以是我的解決方案。

但是,在閱讀this answer(特別是第一個例子)之後,似乎我無法從移動語義中獲益。

我想反正(表兄弟姐妹爲什麼赫克不...)和不喜歡的東西這個代替:

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

現在我驚訝的是MyTask的拷貝構造函數仍然叫(我把打印它以驗證),但由於某種原因,現在處理程序註冊運行良好,我的實例喜歡doSomething()調用。

我試着更詳細地閱讀關於std :: move的內容,以瞭解那裏發生了什麼,但找不到答案。

任何人都可以解釋它嗎? std :: move是不是移動了這個指針?也許它只是造成了登記正確莫名其妙地發生,沒有什麼真正的做與移動嘗試

感謝

編輯

,進一步明確我在問什麼:

我明白使用std :: move並不會影響那裏正在做的事情。

但由於某種原因,它確實讓我的對象在地圖上通過處理程序獲取doSomething()調用。我正在尋找這個理由

在一個側面說明,因爲它可能屬於一個不同的問題 - 是否有任何體面的方式來初始化地圖這種方式沒有兩次創建每個對象的開銷?

+1

這個問題對我來說還不是很清楚。你的例子並沒有什麼意義 - 這個'std :: map'在什麼地方起作用?它和'Handler'有什麼關係?請創建一個真正的[mcve] – AndyG

+0

爲什麼它關係到地圖起作用?並且處理程序註冊創建的任務對象 – 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