我今天需要使用一些遵循这个基本设计的类:
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)是这样的
class A {
MyTask<bool, 128> myTask;
public:
A(int i) {}
};
我想做的是有一个 map ,其中 A 的实例是值
static std::map<int, A> map = {
{42, A(1948)},
{88, A(-17)}
};
首先要澄清一些事情——这段代码需要在实时嵌入式系统上运行,所以出于几个遗留原因,我不允许使用 new 分配内存。
我的问题是 map 中的实际对象不是我明确创建的对象,因此它们没有在 Handler 类中注册(所以我没有得到 Handler::handle 调用的好处)。
我试着想出一个很好的方法来解决这个问题,而不是做一些丑陋的事情,比如首先创建一个 A 数组,然后只指向 map 中的这些对象。
我以前从未使用过 move 语义,但我读过一些关于它们的内容,并认为它们可以成为我的解决方案。
然而,看了之后this answer (特别是第一个示例)似乎我无法从使用 move 语义中真正受益。
无论如何我都试过了(因为为什么不……)并做了这样的事情:
static std::map<int, A> map = {
{42, std::move(A(1948))},
{88, std::move(A(-17))}
};
令我惊讶的是,现在 MyTask 的复制构造函数仍然被调用(我将 print 放入其中进行验证)但出于某种原因现在处理程序注册工作正常并且我的实例享受 doSomething() 调用。
我尝试更深入地阅读 std::move 以了解那里到底发生了什么,但找不到答案。
谁能解释一下? std::move 是否以某种方式 move 了 this 指针?或者它可能只是导致注册以某种方式正确发生并且与 move 尝试无关真实
谢谢
编辑:
进一步澄清我的问题:
我知道 std::move 的使用对那里所做的事情没有贡献。
但出于某种原因,它确实让我的对象在 map 中通过处理程序获得 doSomething() 调用。我正在寻找这个原因
旁注,因为它可能属于不同的问题 - 是否有任何合适的方法以这种方式初始化 map 而无需两次创建每个对象的开销?
最佳答案
你的问题比它需要的要多得多,但我想我理解这里的根本问题。 std::map
构造函数接收一个 initialization_list
,您正在调用 (5) from this list .遍历 initializer_list
时,对象会从 initializer_list
中复制出来,而不是 move ,因为 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{})}
,您将在混合中添加另一个编译器无法轻易优化掉的 move 。
关于c++在据称不应该有好处的地方 move 语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40919319/