2013-05-13 6 views
-6

я эту проблему преобразования с помощью этого кода с помощью C++ 11 стандарт:C++ 11: преобразование Const INT * для Int * с помощью unordered_set :: толкать

#include<unordered_set> 
struct B 
{ 
    int x, y; 
}; 

class A 
{ 
    struct hash 
    { 
     std::size_t operator()(int* const a) const 
     { 
     return std::hash<int>()(*a); 
     } 
    }; 

    struct equal_to 
    { 
     std::size_t operator()(int* const a, int* const b) const 
     { 
     return std::equal_to<int>()(*a, *b); 
     } 
    }; 

    private: 
     std::unordered_set< int*, hash, equal_to > set; 

    public: 
     void push(const B& b) 
     { 
     set.insert(&b.x); 
     } 
}; 

Кто-нибудь знает, почему это? Я могу решить проблему, удалив модификатор «const» в аргументе «push». Но я не хочу этого, потому что аргумент «b» не изменяется.

Редактировать: Мое упрощение кода создало неопубликованный адрес. Я создал структуру B, чтобы удалить ее.

+0

Это не C11. –

+2

Голосование заново. Проблема заключается в 'set.insert (& a)', где 'a' имеет тип' const int & '. Адрес 'a' имеет тип« указатель на const int », но заданный объект ищет« указатель на (модифицируемый) int ». Такая путаница 'const' довольно распространена и требует ответа. –

+2

Не связано с вашим вопросом, но вы храните адрес объекта, который может быть временным объектом в вашем наборе. После того, как 'a', который был передан методу' push', вышел из области действия, адрес недействителен и может привести к повреждению кучи или сбою приложений позже, если на него ссылаются (например, ваш метод 'equal_to'). – pstrjds

ответ

2

Ключ set объявлен как быть указатель на INT, в int*. Но это:

void push(const B& b) 
{ 
    set.insert(&b.x); 
} 

проходит адрес постоянного int, в int const*, следовательно, ошибка компилятора.

Удаление const от аргумента будет устранить ошибку компилятора, как это делает тип ключа int const*, но оба эти решения будут:

  • разрешения какой-либо другая часть программы, с не- const доступ к B экземпляр, который был принят в push(), чтобы изменить значение одного из ключей в наборе и разбить множество инвариант:

    A a; 
    
    B b1{17, 22}; 
    B b2{30, 22}; 
    
    a.push(b1); 
    a.push(b2); 
    
    b1.x = 30; // set no longer contains unique keys. 
    
  • ввести зависимость set от времени жизни объекта, на который ссылается b:

    A a; 
    a.push({14, 23}); // a now contains a dangling pointer. 
    

Самое безопасное решение для хранения int в качестве ключа, см http://ideone.com/KrykZw для онлайн демо (спасибо bitmask для комментариев).


Возможные решения:

  1. Динамически скопировать b.x. Или,
  2. Используйте int const* в качестве ключа. Или предпочтительно (избегая явное динамическое распределение),
  3. Использование int в качестве ключа, вместо int* (см http://ideone.com/KrykZw)
+0

Хранение 'int *' в наборе (хеш-) (или регулярном наборе, если на то пошло), позволяя изменять объект «заостренный объект» и иметь хеш-функцию вычислить хеш на основе указателя на объект, будет не только демонстрировать неопределенное поведение, но и, безусловно, сбой в любой реализации, о которой я могу думать. Ваше третье решение - единственное, что имеет смысл. (Обратите внимание, что 'b.x' может измениться, даже если' b' передается как const ref в 'push'.) – bitmask

+0

Спасибо, 2 вариант - мое любимое решение, потому что я не хочу использовать copy-constructor. – xgbuils

+0

@jefebrondem, какой конструктор копирования? – hmjd

 Смежные вопросы

  • Нет связанных вопросов^_^