2016-03-30 13 views
9

W prostych słowach mam prosty wskaźnik:dla const odniesienia do const wskaźnik wskazujący na const obiektu

int* a; 

teraz chciałbym zmienić wartość tego wskaźnika. Chcę to zrobić w funkcji. Funkcja zapewnia, że ​​nie zmieni obiektu, wskaźnik wskaże, ale zmieni sam wskaźnik. Z tego powodu chciałbym, aby ta funkcja przyjmowała argument w następujący sposób: non-const reference (ponieważ wartość wskaźnika zostanie zmieniona) na wskaźnik niestały (sam wskaźnik można zmienić) wskazując na obiekt const (funkcja zapewnia, że ​​obiekt, ten wskaźnik wskazuje, że nie zostanie zmieniony).

Najprostsza funkcja będzie:

void function(const int*& a){ 
    a = 0; 
} 

ale gdy próbuję wywołać tę funkcję:

int main(){ 
    int* a; 
    function(a); 
    return 0; 
} 

kompilator jest nieszczęśliwy i mówi:

nieważny inicjalizacji nie- const reference typu "const int * &" z wartości r "typu int" * " funkcja (a);

nie mogę zupełnie zrozumieć ten problem, jak dla mnie nie ma udział RValue (I m przechodzącą odniesienie do obiektu, który już istnieje na stosie.)

Pytanie jest, w jaki sposób mogę to zrobić prawidłowo?

Przykład można znaleźć tutaj: https://ideone.com/D45Cid


EDIT:

Zasugerowano, że moje pytanie jest zblizonym do Why isn't it legal to convert "pointer to pointer to non-const" to a "pointer to pointer to const"

moje pytanie jest inny jak nie używam wskaźnik do wskaźnika Używam tylko wskaźnika do obiektu/wartości i zapisuję do niego odniesienie, dlatego sytuacja jak w odpowiedzi na to pytanie:

const char c = 'c'; 
char* pc; 
const char** pcc = &pc; // not allowed 
*pcc = &c; 
*pc = 'C';    // would allow to modify a const object 

Nie jest możliwe w moim przypadku, ponieważ nie mogę zrezygnować z wskaźnika najwyższego poziomu (nie mam takiego wskaźnika).

Ponadto pytałem o ładnym i czystym rozwiązania tego problemu, który nie jest objęty w pytaniu

+1

nie jestem pewien, czy można pomieszaj wskaźnik i odniesienie. Cóż, powinieneś, ale proszę, nie. Nikt nie zrozumie twojego kodu! – hr0m

+0

@ Holt Nie mogę tego zrobić. Jest to prosty przykład, ale w prawdziwym kodzie później wykonuję operacje na tym obiekcie, więc nie mogę zadeklarować wskaźnika jako const – DawidPi

+0

@ hr0m Wskaźnik do wskaźnika jest lepszy, niż wskaźnik do odwołania? Te, moim zdaniem, mają różne znaczenia. – DawidPi

Odpowiedz

9

nie mogę zupełnie zrozumieć ten problem, jak dla mnie nie ma udział RValue (I m przechodzącą odniesienie do obiektu, który już istnieje na stosie.)

int* i const int* to dwie różne rzeczy. Po przejściu pod numer a typu int* do function(const int*&) należy najpierw niejawnie przesłać go do const int*, co jest tymczasowe, tj. Wartość r, i nie może być powiązane z odwołaniami bez ograniczeń. Dlatego kompilator narzeka.

Pytanie brzmi, jak mogę to zrobić właściwie?

Można zmienić typ a lub typ parametru function(), by je dopasować dokładnie (może być const int* jeśli nie zmieni się wartość wskazywanego przez wskaźnik), aby uniknąć niejawna konwersja i zmienną tymczasową . Lub, jak zasugerował @TartanLlama, zwróć nową wartość wskaźnika z function().

+3

Inną opcją jest zwrócenie nowej wartości wskaźnika, może w struct lub pair, jeśli jest już zwracana wartość. – TartanLlama

2

Nie jestem do końca pewien, co chcesz osiągnąć.

Ten fragment kodu może ci jednak pomóc. Powinien wskazywać, jak możesz robić, co chcesz.

#include <iostream> 

using namespace std; 

int A = 1; 
int B = 2; 
int C = 3; 

void change_pointer(int*& a){ 
    // your pointer will point to B 
    a = &B; 
} 

void change_value(int* const& a) { 
    // the reference to pointer is constant, but not the value 
    // a=&C; wouldn't work 
    *a = C; 
} 

int main(){ 
    int* a; 
    // at this point a is an undefined pointer to an int 
    // *a is unallocated space 

    a=&A; // you initialize the pointer with an other pointer 
    cout << "*a = " << *a << ", A = " << A << ", B = " << B << ", C = " << C << endl; 

    change_pointer(a); // makes 'a' point to B 
    cout << "*a = " << *a << ", A = " << A << ", B = " << B << ", C = " << C << endl; 

    change_value(a); // changes the value pointed by a to C (in the process modifying the value of B) 
    cout << "*a = " << *a << ", A = " << A << ", B = " << B << ", C = " << C << endl; 

    return *a; 
} 

EDIT: W odpowiedzi na komentarz TartanLlama użytkownika.

Jedynym sposobem, widzę do pracy z „non const ref” do „non wskaźnik const” do „const int” jest za pomocą typedef:

#include <iostream> 

using namespace std; 

typedef const int const_int_t; 

const_int_t A = 1; 
const_int_t B = 2; 

void change_pointer(const_int_t*& a){ 
    // your pointer will point to B 
    a = &B; 
} 

int main(){ 
    const_int_t* a; 

    a=&A; // you initialize the pointer with an other pointer 
    cout << "*a = " << *a << ", A = " << A << ", B = " << B << endl; 

    change_pointer(a); // makes 'a' point to B 
    cout << "*a = " << *a << ", A = " << A << ", B = " << B << endl; 

    return *a; 
} 
+1

Tego nie chce OP. On chce non-const odwołanie do niestałego wskaźnika do const 'int'. – TartanLlama

+0

@TartanLlama: dzięki za oczyszczenie rzeczy dla mnie. Dodałem rozwiązanie za pomocą typedef. –

+1

Nie tego też chce, a typedef niczego nie dodaje. Problem polega na uzyskaniu niestanowiącego stałych odniesienia do wskaźnika niestałego do stałej "int" z nieokreślonego poirtera do niestanowiącego stałego "int". – TartanLlama