在移动被认为安全之前得到右值参考的地址?

时间:2013-08-07 20:32:29

标签: c++ c++11 move-semantics rvalue-reference

我正在玩Move Semantics和[r | l]值引用,以学习如何在真实世界的程序中使用它们。请考虑以下代码:

// Item is a heavy class having move ctor and assignment but no copy. 
std::map<std::string, Item*> lookup;
std::forward_list<Item> items;
void FooClass::addItem(Item&& d) {
    if (lookup.find(d.getName()) == lookup.end()) {
        lookup[d.getName()] = &d;    //<== not safe after move?
        items.push_front(std::move(d));
    }
}

我正在获取Item&&的地址并将其存储在指针中。然后将数据移至std::forward_listitems)。我假设调用移动赋值不会影响对象的地址。那是对的吗?虽然移动后d的内容不再有效。这是查找表(lookup)的内容不正确。

我假设我必须重新订购a)添加查找项目和b)移动实际数据。上面的代码并不理智。这是对的吗?

此外,我不明白为什么我必须在那里说std::move。编译器应该知道d是一个右值引用。所以它应该调用std::forward_list<T>::push_front(T&&)并移动赋值...

2 个答案:

答案 0 :(得分:5)

    lookup.[d.getName()] = &d;    //<== not safe after move?

这完全不安全,但不仅仅是因为此举。与你的问题的标题相反,你没有获取右值引用的地址,你正在获取左值的地址,但是在函数返回后很快就会超出范围,这将留下一个悬空指针。考虑:

FooClass f;
f.addItem( Item() );

这会将临时地址添加到地图中,因此,如果您取消引用指针,则程序具有未定义的行为,这是不安全的缩影。

下一行的移动可能会使事情变得更糟,因为地图中指针引用的对象可能会被移动修改,在地图中留下指向移动的Item的指针,但是与函数返回后超出范围的未定义行为相比,这没什么。

使代码安全是微不足道的,所以没有理由按照你的方式编写代码。

    items.push_front(std::move(d));
    auto& item = items.front();
    lookup[item.getName()] = &item;

现在地图中的指针指的是一个不会超出范围的对象。只要元素在forward_list

中,指针就会有效

答案 1 :(得分:1)

我会删除items并将lookup更改为按值存储Item,如下所示:

using Lookup = std::map<std::string, Item>;
Lookup lookup;

void addItem(Item&& d)
{ lookup.insert(std::pair<std::string const&, Item&&>{d.getName(), std::move(d)}); }