2011-10-18 9 views
5

otrzymuję następujący błąd error: invalid conversion from ‘const int*’ to ‘int*’ Poniżej znajduje mój programNieprawidłowy konwersji z „const int *” do „int *” biorąc std :: set adres elementu

#include <set> 
int main (int argc, char **argv) { 
    std::set<int> intSet; 
    intSet.insert(1); 
    intSet.insert(2); 
    intSet.insert(3); 
    intSet.insert(4); 
    intSet.insert(5); 

    int *pAddress = &(*(intSet.find(4))); 
} 

Chcę adres elementu w std::set, Ten kod nie daje żadnego błędu kompilacji z kompilatorem Microsoft, ale g++ podaje ten błąd kompilacji.

+0

Elementy std :: set są stałe, w twoim przypadku stałe liczby całkowite. jakiego kompilatora MS używasz? – cpx

+0

Visual Studio 2005 – Avinash

+2

To błąd w VS2005, który pozwala na modyfikację std :: set. – cpx

Odpowiedz

5

To dlatego, że każdy element std::set jest przechowywany jako T const, a implementacja ma ku temu powód.

Od std::set zawiera dokładnie jedną kopię wartości. Musi to być niezmienne, aby można było zmienić jego wartość na coś, co już istnieje w zestawie.

Nawet jeśli elementy były zmienny, nie byłby w stanie zmiana wartości, ponieważ std::set::find jest funkcją const członkiem, a więc w tej funkcji intSet jest niezmienne i skutecznie każdy elementy staną niezmienne również, w tym iterator, który zwraca i dzięki któremu można zmienić wartość w miejscu wywołania.

Jedynym chcą wziąć adres to:

int const *paddress = &(*(intSet.find(4))); //const int* is same as int const* 

Nie używaj const_cast choć

//DANGEROUS - DONT DO IT 
int *paddress = const_cast<int*>(&(*(intSet.find(4)))); //will compile, 
                 //but it is dangerous! 

//you might accidentally write 
*paddress = 10; //undefined behaviour, 
       //though the compiler will let you write this 
+0

Ponieważ po prostu potrzebuję adresu elementu, czy byłoby dobrze, aby typować na niedziałające – Avinash

+0

@Avinash: I dodał więcej rzeczy do mojej odpowiedzi. – Nawaz

+0

Elementy zestawu są przechowywane jako 'T', a nie' T const' i mogą być modyfikowane, o ile nie wpływa to na kolejność. Zachowanie GCC, choć bezpieczniejsze, jest niezgodne. –

0

Wartości zestawu mają być niezmienne tak, że klasa może gwarantują, że wszystkie elementy są unikalne. Podanie wskaźnika innego niż const spowodowałoby, że zbyt łatwo byłoby zmienić wartość, która przerwałaby projekt klasy zestawu szablonów (http://msdn.microsoft.com/en-us/library/e8wh7665(VS.80).aspx).

należy zmienić ostatni wiersz mieć "const" przed nim tak:

const int *pAddress = &(*(intSet.find(4))); 

FYI: Twój kod daje identyczny błąd kompilacji w Visual Studio 2010.

1

GCC definesset::iterator to set::const_iterator, uniemożliwiając powiązanie odniesienia lub wskaźnika innego niż const z wynikiem set::find(). Takie zachowanie jest dozwolone przez C++ 11 (który stwierdza, że ​​klucze są niezmienne, i że set::iterator jest iteratorem stałym), ale było niepoprawne w C++ 03.

W C++ 03 nie należy modyfikować elementów zestawu, ponieważ może to spowodować przerwanie porządkowania elementów w nim. W niektórych przypadkach możesz chcieć - jeśli typ jest klasą i tylko niektórzy członkowie są używani do definiowania kolejności, wtedy można było modyfikować innych członków. Standard C++ 03 pozwala na to, ale musisz uważać, aby nie modyfikować kolejności, ponieważ spowoduje to niezdefiniowane zachowanie. W C++ 11 jest to zabronione, a implementacja może temu zapobiec.

W twoim przypadku nie możesz legalnie zmienić wartości, więc możesz naprawić swój kod dla C++ 11, a także poprawić jego bezpieczeństwo, wiążąc wskaźnik ze stałą.

int const *pAddress = &(*(intSet.find(4))); 
+2

Który standard pozwala na to, ponieważ w n3225 asocjacyjnych wymaganiach kontenera jest całkiem jasne: "Dla' set' i 'multiset' typ wartości jest taki sam jak typ klucza ... Klucze w asocjacyjnym kontenerze są ** niezmienne * *. " oraz "W przypadku kontenerów asocjacyjnych, w których typ wartości jest taki sam jak typ klucza, zarówno iterator, jak i const_iterator są ** stałymi iteratorami **. Nie jest to określone, czy iterator i const_iterator są tego samego typu." - Wspomniano nawet w dyskusji o zgłoszeniu błędu, że GCC jest uważane za zgodne. – UncleBens

+0

@UncleBens: Patrzyłem na C++ 03, który nie ma tych klauzul, ale określa, że ​​'iterator' to" typ iteratora wskazujący na 'T'" dla wszystkich kontenerów. Zaktualizuję moją odpowiedź na C++ 11. –

Powiązane problemy