据称不应该有好处的C ++移动语义

c++ move semantics where allegedly there shouldn't be benefit

本文关键字:移动 语义 不应该      更新时间:2023-10-16

我今天需要使用一些遵循此基本设计的类:

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的示例为a是值的地图

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

首先要澄清某些内容 - 此代码需要在实时嵌入式系统上运行,因此由于多种遗产原因,我不允许使用新的内存分配内存。

我的问题是,地图中的实际对象不是我明确创建的对象,因此它们没有在处理程序类中注册(因此我没有从Handler :: Wandle Call中受益)。

我尝试找到一种很好的方法来解决这个问题,而不要做丑陋的事情,例如首先创建一个数组,然后只指向地图中的这些对象。

我以前从未使用过移动语义,但我已经阅读了一些有关它们的信息,并认为它们可以成为我的解决方案。

但是,在阅读了此答案之后(特定于第一个示例),似乎我真的无法从使用移动语义中受益。

我无论如何都尝试过(因为为什么不……),而是这样做的:

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

现在令我惊讶的是,MyTask的复制构造函数仍然被打电话(我在其中打印以验证),但由于某种原因,处理程序注册效果很好,我的实例很喜欢dosomething()呼叫。

我尝试更彻底地阅读有关std ::的动作,以了解那里到底发生了什么,但找不到答案。

任何人都可以解释吗?std ::移动是否会以某种方式移动指针?也许这只是导致注册正确地发生,并且没有任何 real 与移动尝试

有关

谢谢

编辑

进一步澄清我要问的内容:

我了解STD :: Move的使用并没有为在那里所做的事情做出贡献。

,但由于某种原因,它确实在地图中吸引了我的对象,以通过处理程序获得Dosomething()调用。我正在寻找这个原因

在旁注上,因为它可能属于一个不同的问题 - 是否有任何不错的方法可以以这种方式初始化地图,而不会两次创建每个对象的开销?

您的问题中的问题要多得多,但我认为我在这里理解根部问题。std::map构造函数接收一个initialization_list,您从此列表中调用(5)。当迭代迭代而不是移动时,将对象复制在initializer_list中,因为initializer_list的副本未复制基础对象。同样的影响其他std容器,这是vector的示例。(实时链接)

#include <vector>
#include <iostream>
struct Printer {
    Printer() { std::cout << "default ctorn"; }
    Printer(const Printer&) { std::cout << "copyn"; }
    Printer(Printer&&) { std::cout << "moven"; }
};
int main() {
    std::vector<Printer> v = {Printer{}};
}

如果您使用{std::move(Printer{})},您将在编译器无法轻易优化的混合物中添加另一个动作。