2013-07-11 30 views
12

此代码混淆了我:复制/移动std :: map中的键/值类型的要求?

struct foo { 
    int i; 

    foo(int j) : i(j) {} 

    foo(const foo &) = delete; 
    foo(foo &&) = delete; 
    foo &operator=(const foo&) = delete; 
    foo &operator=(foo&&) = delete; 
}; 

bool operator<(const foo &f1, const foo &f2) 
{ 
    return f1.i < f2.i; 
} 

int main(int argc, char **argv) 
{ 
    std::map<foo,int> f; 
    std::map<foo,int> f2 = f; //error (as expected) 
    std::map<foo,int> f3 = std::move(f); //no error (why?) 
    return 0; 
} 

因为我没有得到任何错误,它似乎移动地图没有按键对象被创建(甚至是移动的另一个关键对象到它不重要)等。

为什么不呢?我可以依赖C++ 11标准的这种行为吗?

更一般地说,在密钥和值类型以及在什么条件下,std::map位置上有什么复制/移动要求?

+0

移动地图放置关键和值_no_要求。 –

+1

@MooingDuck,如果分配器类型不会传播 –

+0

啊,那么分配器就可以搞砸了。 –

回答

14

将一张地图复制分配给另一张需要复制每个项目。由于您无法复制项目,因此无法复制 - 分配地图。

无论实际地图对象是在运行时空是不重要的,因为这些是纯粹静态考虑,完全由类型的对象的确定。

(这就像问为什么sin(0)需要时会产生明显的结果是一个整数,浮点单元)。

移动整个地图,在另一方面,是很好的,因为容器是基于节点和没有实际值是变异的,只是节点。实际上,移动构建或移动分配基于节点的容器不需要元件可复制可移动根本不可分配。

(这应该是用于管理以合适的方式动态存储器,如通过std::allocator<value_type>所有容器真实的,但它当然不是像std::array是真的,这将是有趣它是否会举行对于std::dynarray,并作为@Jonathan Wakely指出,如果分配方案是不是能够移动节点的批发。)

+4

如果'allocator_traits :: propagate_on_container_move_assignment :: value'为false,移动指定一个类型为'M'的地图要求元素类型为'MoveInsertable'到'M' –

+0

@JonathanWakely:哦,亲爱的。是的,这是一个很好的观点。这一切都取决于分配器! –

+3

该死的该死的分配器: - \ –

3

没有错误,因为只有map移动的map不是元素。只是指向元素分配