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

sor*_*h-r 1 c++ rvalue-reference move-semantics c++11

我正在玩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));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Jon*_*ely 6

    lookup.[d.getName()] = &d;    //<== not safe after move?
Run Code Online (Sandbox Code Playgroud)

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

FooClass f;
f.addItem( Item() );
Run Code Online (Sandbox Code Playgroud)

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

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

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

    items.push_front(std::move(d));
    auto& item = items.front();
    lookup[item.getName()] = &item;
Run Code Online (Sandbox Code Playgroud)

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