2016-12-01 45 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