假设如下:
template<typename Item>
class Pipeline
{
[...]
void connect(OutputSide<Item> first, InputSide<Item> second)
{
Queue<Item> queue;
first.setOutputQueue(&queue);
second.setInputQueue(&queue);
queues.push_back(std::move(queue));
}
[...]
std::vector<Queue<Item> > queues;
};
指向队列的指针是否仍然可以在&#34;第一个&#34;和&#34;第二&#34;搬家后?
答案 0 :(得分:9)
std :: move会使指针无效吗?
没有。移动后对象仍然存在,因此任何指向该对象的指针仍然有效。如果Queue
被明智地实施,那么从它移动应该使它处于有效状态(即,可以安全地销毁或重新分配它);但可能会改变其状态(可能会将其留空)。
移动后,指向队列的指针仍会在“第一个”和“第二个”工作吗?
没有。它们将指向已被移动的本地对象;如上所述,您不能在移动后对该对象的状态做出任何假设。
比这更糟糕的是,当函数返回时,它被破坏,让指针悬空。它们现在无效,不指向任何对象,使用它们会产生未定义的行为。
也许您希望他们指向已移入queues
的对象:
queues.push_back(std::move(queue));
first.setOutputQueue(&queue.back());
second.setInputQueue(&queue.back());
但是,由于queues
是一个向量,当队列接下来重新分配其内存时,这些指针将失效。
要解决此问题,请使用deque
或list
之类的容器,该容器在插入后不会移动其元素。或者,以额外的间接级别为代价,您可以存储(智能)指针而不是对象,如Danvil的回答所述。
答案 1 :(得分:4)
指针不起作用,因为queue
是一个本地对象,将在connect
的末尾删除。即使使用std::move
,您仍然可以在新的内存位置创建新对象。它将尝试尽可能多地使用“旧”对象。
此外,整个事情根本无法使用std::move
,因为push_back
可能需要重新分配。因此,调用connect
可能会使所有旧指针无效。
一种可能的解决方案是在堆上创建Queue
个对象。以下建议使用C ++ 11:
#include <memory>
template<typename Item>
class Pipeline
{
[...]
void connect(OutputSide<Item> first, InputSide<Item> second)
{
auto queue = std::make_shared<Queue<Item>>();
first.setOutputQueue(queue);
second.setInputQueue(queue);
queues.push_back(queue);
}
[...]
std::vector<std::shared_ptr<Queue<Item>>> queues;
};
答案 2 :(得分:2)
其他人提供了很好的详细解释,但是你的问题表明你并不完全理解move
做了什么,或者它的目的是什么。我会试着用简单的词语来描述它。
move
意味着移动。但是什么可以移动?一旦在某处分配了对象,就无法移动它。回想一下最近添加的新的moving-construtcor,它类似于复制构造函数。
所以,关于&#34;内容&#34;一个对象。复制和移动构造函数都是针对&#34;内容&#34;进行操作的。 std::move
也是如此。它意味着将一个对象的内容移动到目标中,与copy
相反,它意味着不在原始位置留下任何内容痕迹。
它意味着可以在任何地方使用某些东西迫使我们制作一份我们并不真正关心的副本以及我们真正想要实际省略的内容,并且只有内容已经在目标中的地方。
即使用&#34;移动&#34;表示副本将,内容将移至,原始文件将被清除(有时可能会跳过某些步骤,但仍然,这是move
)的基本思想。
这清楚地表明,即使原始文件存活,任何指向原始对象的指针都会不指向到收到内容的目标。充其量,他们会指出刚刚被清除的原始事物。在最坏的情况下,它将指向一个完全无法使用的东西。
现在看看你的代码。它填充queue
,然后将指针指向原始,然后moves
queue
。
我希望现在能够清楚地知道发生了什么,以及你可以用它做些什么。