C++ 将对象从一个无序映射移动到另一个容器

C++ 将对象从一个无序映射移动到另一个容器,c++,iterator,move-semantics,unordered-map,C++,Iterator,Move Semantics,Unordered Map,我的问题是安全问题。我搜索了cplusplus.com和cppreference.com,它们似乎在std::move期间缺乏迭代器安全性。特别是:使用对象已移动的迭代器调用std::unordered_map::erase(迭代器)安全吗?示例代码: #include <unordered_map> #include <string> #include <vector> #include <iostream> #include <memor

我的问题是安全问题。我搜索了cplusplus.com和cppreference.com,它们似乎在std::move期间缺乏迭代器安全性。特别是:使用对象已移动的迭代器调用std::unordered_map::erase(迭代器)安全吗?示例代码:

#include <unordered_map>
#include <string>
#include <vector>
#include <iostream>
#include <memory>

class A {
public:
    A() : name("default ctored"), value(-1) {}
    A(const std::string& name, int value) : name(name), value(value) { }
    std::string name;
    int value;
};
typedef std::shared_ptr<const A> ConstAPtr;

int main(int argc, char **argv) {
    // containers keyed by shared_ptr are keyed by the raw pointer address
    std::unordered_map<ConstAPtr, int> valued_objects;

    for ( int i = 0; i < 10; ++i ) {
        // creates 5 objects named "name 0", and 5 named "name 1"
        std::string name("name ");
        name += std::to_string(i % 2);

        valued_objects[std::make_shared<A>(std::move(name), i)] = i * 5;
    }

    // Later somewhere else we need to transform the map to be keyed differently
    // while retaining the values for each object

    typedef std::pair<ConstAPtr, int> ObjValue;

    std::unordered_map<std::string, std::vector<ObjValue> > named_objects;

    std::cout << "moving..." << std::endl;

    // No increment since we're using .erase() and don't want to skip objects.
    for ( auto it = valued_objects.begin(); it != valued_objects.end(); ) {
        std::cout << it->first->name << "\t" << it->first.value << "\t" << it->second << std::endl;

        // Get named_vec.
        std::vector<ObjValue>& v = named_objects[it->first->name];
        // move object :: IS THIS SAFE??
        v.push_back(std::move(*it));

        // And then... is this also safe???
        it = valued_objects.erase(it);
    }

    std::cout << "checking... " << named_objects.size() << std::endl;
    for ( auto it = named_objects.begin(); it != named_objects.end(); ++it ) {
        std::cout << it->first << " (" << it->second.size() << ")" << std::endl;
        for ( auto pair : it->second ) {
            std::cout << "\t" << pair.first->name << "\t" << pair.first->value << "\t" << pair.second << std::endl;
        }
    }

    std::cout << "double check... " << valued_objects.size() << std::endl;
    for ( auto it : valued_objects ) {
        std::cout << it.first->name << " (" << it.second << ")" << std::endl;
    }

    return 0;
}
#包括
#包括
#包括
#包括
#包括
甲级{
公众:
A()
(const std::string&name,int-value):名称(name),值(value){}
std::字符串名;
int值;
};
typedef std::shared_ptr ConstAPtr;
int main(int argc,字符**argv){
//由shared_ptr键控的容器由原始指针地址键控
std::无序的映射值对象;
对于(int i=0;i<10;++i){
//创建5个名为“名称0”的对象和5个名为“名称1”的对象
std::字符串名称(“名称”);
name+=std::to_字符串(i%2);
有值对象[std::make_shared(std::move(name),i)]=i*5;
}
//稍后,在其他地方,我们需要变换贴图,使其以不同的方式设置关键帧
//同时保留每个对象的值
typedef std::对ObjValue;
std::命名为_对象的无序_映射;
标准::cout

是的,它是安全的,因为它实际上不会修改密钥。它不能修改,因为密钥是常量。
*it
的类型是
std::pair
。移动它时,第一个成员(const ConstAPtr
)没有实际移动。它通过
std::move
转换为r值,并成为
const ConstAPtr&&
。但这与move构造函数不匹配,后者需要一个非const
ConstAPtr&
。因此将调用copy构造函数。

因此它实际上为std::pair调用了一个copy构造函数?所以让我们说第二个模板ate参数是一个复杂的结构…因此,我不会从std::move()中获得任何好处在这种情况下?因此我需要将复杂结构移动到一个新的对中?@inetknght:这是我最初的想法。然而,我现在正在做的测试似乎表明情况并非如此。当我创建一个
std::pair
并对其使用
std::move
时,第二个字符串似乎实际上是空的,尽管fir是空的st仍然像预期的那样完整。我需要进一步调查这一点。在阅读您的编辑之后——因此第一个对象确实被复制了,但第二个对象被移动了。嗯……因此,如果第一个对象是一个复杂的结构,那可能会很糟糕。在使用共享的\u ptr时,我想知道互斥的开销,但这超出了本文的范围感谢你的帮助!
// move object :: IS THIS SAFE??
v.push_back(std::move(*it));