c ++移动语义,据说不应该有益

时间:2016-12-01 19:56:28

标签: c++ c++11 move

我今天需要使用一些遵循这个基本设计的课程:

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)}
 };

首先澄清一些事情 - 这段代码需要在实时嵌入式系统上运行,因此我不允许使用new来分配内存,原因有几个。

我的问题是地图中的实际对象不是我明确创建的对象,因此它们没有在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 个答案:

答案 0 :(得分: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{})},您将在混合中添加另一个移动,编译器无法轻松优化。