2017-01-26 86 views
9

Kwestia

Poniższy kod nie kompiluje w C++ 11 (ani C++ 14). Rozumiem wyjście błędów z kompilatora, ale dlaczego nie jest to dozwolone przez standard?Dlaczego jest to nielegalne: kopiowanie wektor wskaźników do wektora wskaźniki do stałych

//main.cpp 

#include <vector> 

int main(void) 
{ 
    double a = 3.0; 
    double b = 3.0; 

    //It works with mere pointers 
    const double* ptrToConst = &a; 
    /***/ double* ptrToObj = &a; 
// ptrToObj = ptrToConst; //Illegal : that's understandable… 
    ptrToConst = ptrToObj; //Works 

    //But the same doesn't work with vectors to pointers 
    std::vector<const double*> ptrsToConst = {&a, &b}; 
    std::vector</***/ double*> ptrsToObj = {&a, &b}; 
// ptrsToObj = ptrsToConst; //Illegal : that's understandable 
    ptrsToConst = ptrsToObj; //Illegal : but why?! 
} 

Błąd pochodzi z linii ptrsToConst = ptrsToObj. Rzeczywiście, nie wydaje się możliwe skopiowanie wektora wskaźników std::vector<T*> do wektora wskaźników do stałych std::vector<const T*>. Należy pamiętać, że w obu przypadkach same wskaźniki są stałe: , a nie.

Dlaczego ta operacja byłaby nielegalna? Jaka byłaby najbardziej elegancka praca?


Dalsze szczegóły

Gdybym skompilować powołując clang++ --std=c++11 main.cpp następujący komunikat o błędzie wyświetla:

main.cpp:19:17: error: no viable overloaded '=' 
    ptrsToConst = ptrsToObj; //Illegal : but why?! 
    ~~~~~~~~~~~^~~~~~~~~~ 
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:436:7: note: candidate 
     function not viable: no known conversion from 'vector<double *, allocator<double *>>' to 'const 
     vector<const double *, allocator<const double *>>' for 1st argument 
     operator=(const vector& __x); 
    ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:448:7: note: candidate 
     function not viable: no known conversion from 'vector<double *, allocator<double *>>' to 'vector<const 
     double *, allocator<const double *>>' for 1st argument 
     operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move()) 
    ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h:470:7: note: candidate 
     function not viable: no known conversion from 'std::vector<double *>' to 'initializer_list<value_type>' (aka 
     'initializer_list<const double *>') for 1st argument 
     operator=(initializer_list<value_type> __l) 
    ^
1 error generated. 

Trying to samo z gcc (g ++) przyczynia się do zaostrzenia podobnych komunikatów o błędach.

Najwyraźniej implementowane wektory drogi nie pozwalają na operację, którą próbuję wykonać. Jednak jest to bezpieczna operacja dotycząca poprawności stałej, prawda?

+3

'std :: vector ' nie jest cv wykwalifikowany wersję 'std :: vector ' – imreal

+2

'std :: vector ' i 'std :: vector ' są zupełnie różnymi i niezwiązanymi typami. Zwłaszcza, że ​​nie można zagwarantować, że żadna z nich nie jest specjalną implementacją klasy szablonów. –

+0

Eleganckie rozwiązanie może polegać na przechowywaniu elementów w 'std :: vector', a następnie użyciu iteratorów' const', gdy nie chcesz zmieniać danych. – wally

Odpowiedz

11

Możesz to zrobić, ale nie z operator=. Potrzebujesz funkcji członkowskiej assign, która wykonuje konwersję na każdym pojedynczym elemencie.

ptrsToConst.assign(ptrsToObj.begin(), ptrsToObj.end()); 
+0

Może chcesz dodać, że przesłoni to zawartość wektora const za pomocą kopii z wektora niestałego. I że nie zadziała z przypisaniem referencji. –

+0

@BenVoigt Czy kopiowanie 'std :: vector ' na 'std :: vector ' normalny proces? Czy raczej funkcja 'assign' jest tylko obejściem dla nietypowego procesu kopiowania, który nie jest zalecany w języku C++? Obawiam się wydajności i szybkości 'assign()' – Admia

+1

@Admia: 'assign' jest używane, gdy konieczna jest konwersja elementów. Jest szablonowy, więc będzie niezwykle wydajny/szybki. –

-2

Nie jestem pewien, ale może C++ kopie std::vector<T*> obiekt do std::vector<const T*> przedmiot przez odniesienie. Oznacza to, że C++ nie przydziela nowej pamięci dla nowego obiektu zbudowanego z std::vector<const T*>. Ten nowy obiekt zbudowany z std::vector<const T*> byłby inną nazwą (lub odniesieniem) do starego obiektu o nazwie std::vector<T*>. Wtedy ma sens, dlaczego powstaje błąd. Ponieważ obiekt std::vector<T*> może zmienić to, na co wskazuje, jednak obiekt std::vector<const T*> nie może zmienić tego, na co wskazuje.

+2

Nie, nie robi tego. –

+0

To jest po prostu złe. – user3721426

4

Ponieważ jest to implementacja std::vector: operator przypisania wymaga, aby drugi operand był tego samego typu. I vector<double *> i vector<const double *> są innego typu, ponieważ double i const double są różne, nawet jeśli są kompatybilne.

Można by sobie wyobrazić, aby rozluźnić to wymaganie tylko w przypadku zgodnych typów, ale byłoby to bardziej skomplikowane, gdy implementacja standardowych kontenerów jest już wystarczająco złożona (wystarczy przeczytać nagłówek wektorowy raz ...), a żaden z pisarzy biblioteki, a standardowy komitet uznał to za konieczne.

Jeśli naprawdę potrzebujesz, to trzeba będzie napisać niestandardową implementację ...