2013-03-29 3 views
8

Я знаю, что это ужасная идея изменить ключ объекта в ассоциативном контейнере, но мне интересно, где именно стандарт запрещает мне это делать. Рассмотрим:Почему бы не изменить ключ ассоциативного контейнера?

#include <map> 
#include <memory> 

struct X { int i; }; 

struct lt 
{ 
    bool operator()(const std::shared_ptr<X>& lhs, 
        const std::shared_ptr<X>& rhs) const 
    { 
    return lhs->i < rhs->i; 
    } 
}; 

int main() 
{ 
    std::map< std::shared_ptr<X>, int, lt > m; 
    auto x = std::make_shared<X>(); 
    x->i = 1; 
    m.insert(std::make_pair(x, 2)); 

    x->i = 42; // change key wrt the container! 
} 

Я полагаю, что выше должно быть незаконным, но я читал стандарт в течение некоторого времени, и я не могу найти ничего, что на самом деле делает незаконным. Где это? Или он скрывается в будущем отчете о дефектах?

+0

std :: map имеет внутреннее строение дерева. Если вы измените ключ, внутренняя структура неверна, и поиск не будет работать, потому что вы пойдете по неправильному пути. – Felics

+0

@ Феликс: Это был не вопрос. –

+0

В «Эффективном STL» С. Майерса есть целая глава именно по этой проблеме (см. Пункт 22). Самое смешное в том, что, хотя довольно сложно разрушить внутреннюю структуру карты (поскольку тип элемента карты - «пара ')), вам придется использовать для этого какое-то псевдонимы - очень легко обмануть набор и мультимножество, потому что вы можете назначить '* it', когда' it' является (multi) set :: iterator. – shakurov

ответ

9

Это вводит Неопределенное поведение в вашей программе, если вы изменяете значения таким образом, чтобы сравнение любых двух ключей было различным после изменения в соответствии с указанным вами компаратором.

в соответствии с пунктом 23.2.4/3 C++ 11 стандарта на ([associative.reqmts]):

Фраза «эквивалентность ключей» означает отношение эквивалентности, введенное сравнение и не operator== на клавиши. То есть два ключа k1 и k2 считаются эквивалентными, если для сравнения объект comp, comp(k1, k2) == false && comp(k2, k1) == false. Для любых двух ключей k1 и k2 в тот же контейнер, вызывающий comp(k1, k2) должен всегда возвращать то же значение.

+0

Упс. Не видел этого. : D – Nawaz

+1

+1 и принято, но почему это не выделенное предложение, его собственная маркерная точка и вместо этого зацикливается позади и в контексте «эквивалентности ключей»? Странный. –

+5

@ DanielFrey: Я не знаю, но мне кажется, что весь Стандарт стремится похоронить соответствующие предложения где-то там, где их трудно обнаружить;) –