Przekazywanie odniesień do wskaźników w C++

Z tego, co wiem, nie ma powodu, dla którego nie powinienem przekazywać odniesienia do wskaźnika w C++. Jednak moje próby w tym kierunku zawodzą i nie mam pojęcia dlaczego.

To właśnie robię:

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}

I dostaję ten błąd:

Nie można przekonwertować parametru 1 z 'std::string *' na 'std:: string * &'

Author: gsamaras, 2009-05-05

10 answers

Twoja funkcja oczekuje odniesienia do rzeczywistego wskaźnika łańcuchowego w zakresie wywołania, a nie anonimowego wskaźnika łańcuchowego. Tak więc:

string s;
string* _s = &s;
myfunc(_s);

Powinien się dobrze skompilować.

Jest to jednak przydatne tylko wtedy, gdy zamierzasz zmodyfikować wskaźnik, który PRZEKAZUJESZ do funkcji. Jeśli zamierzasz zmodyfikować sam ciąg znaków, powinieneś użyć odwołania do niego zgodnie z sugestią. Mając to na uwadze, powinno być bardziej oczywiste, dlaczego kompilator narzeka na twój oryginalny kod. W Twoim kodzie wskaźnik jest tworzony "w locie", modyfikowanie tego wskaźnika nie miałoby żadnych konsekwencji i nie jest to zamierzone. Idea odniesienia (vs. wskaźnik) polega na tym, że odniesienie zawsze wskazuje na rzeczywisty obiekt.

 103
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-04 01:33:16

Problem polega na tym, że próbujesz powiązać tymczasowe odniesienie z referencją, na co C++ nie pozwala, chyba że odniesienie to const.

Więc możesz wykonać jedną z następujących czynności:

void myfunc(string*& val)
{
    // Do stuff to the string pointer
}


void myfunc2(string* const& val)
{
    // Do stuff to the string pointer
}

int main()
// sometime later 
{
    // ...
    string s;
    string* ps = &s;

    myfunc( ps);   // OK because ps is not a temporary
    myfunc2( &s);  // OK because the parameter is a const&
    // ...

    return 0;
}
 78
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-05 05:21:39

Zmień na:

  std::string s;
  std::string* pS = &s;
  myfunc(pS);

EDIT:

Nazywa się to ref-to-pointer i nie można przekazać adresu tymczasowego jako odniesienia do funkcji. (chyba że jest const reference).

Chociaż pokazałem std::string* pS = &s; (Wskaźnik do zmiennej lokalnej), jej typowe użycie byłoby : gdy chcesz, aby callee zmieniało sam wskaźnik, a nie obiekt, do którego wskazuje. Na przykład funkcja, która przydziela pamięć i przypisuje adres bloku pamięci przydzielonego do jego argumentu, musi mieć odniesienie do a pointer, or a pointer to pointer:

void myfunc(string*& val)
{
//val is valid even after function call
   val = new std::string("Test");

}
 7
Author: aJ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-05 05:48:09

&s tworzy tymczasowy wskaźnik na string i nie można nawiązywać do tymczasowego obiektu.

 5
Author: n0rd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-05 05:18:50

Try:

void myfunc(string& val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(s);
    // ...
}

Lub

void myfunc(string* val)
{
    // Do stuff to the string pointer
}

// sometime later 
{
    // ...
    string s;
    myfunc(&s);
    // ...
}
 3
Author: Sake,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-05 05:09:39

EDIT: trochę eksperymentowałem i odkryłem, że rzeczy są nieco subtelniejsze, niż myślałem. Oto, co teraz uważam za trafną odpowiedź.

&s nie jest lvalue, więc nie można utworzyć odniesienia do niego, chyba że typ odniesienia jest odniesieniem do const. Więc na przykład, nie możesz zrobić

string * &r = &s;

But you can do

string * const &r = &s;

Jeśli umieścisz podobną deklarację w nagłówku funkcji, będzie działać.

void myfunc(string * const &a) { ... }

Jest jeszcze jedna kwestia, a mianowicie tymczasowe. Na reguła jest taka, że można uzyskać odniesienie do tymczasowej tylko wtedy, gdy jest to const. Tak więc w tym przypadku można argumentować, że &s jest tymczasowym, a więc musi być zadeklarowane const w prototypie funkcji. Z praktycznego punktu widzenia nie ma to znaczenia w tym przypadku. (Jest to wartość R lub tymczasowa. Tak czy inaczej, obowiązuje ta sama zasada.) Jednak, ściśle mówiąc, myślę, że nie jest to tymczasowa, ale rvalue. Zastanawiam się, czy istnieje sposób, aby odróżnić te dwa. (Być może jest to po prostu zdefiniowane że wszystkie tymczasowe są wartościami r, a wszystkie inne niż lvalues są wartościami tymczasowymi. Nie jestem ekspertem od standardów.)

To powiedziawszy, twój problem jest prawdopodobnie na wyższym poziomie. Dlaczego chcesz mieć odniesienie do adresu s? Jeśli chcesz mieć odniesienie do wskaźnika do s, musisz zdefiniować wskaźnik jak w

string *p = &s;
myfunc(p);

Jeśli chcesz odniesienie do s lub wskaźnik do s, zrób prostą rzecz.

 2
Author: Ari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-05 06:00:23

Użyłem właśnie odniesienia do wskaźnika, aby wszystkie wskaźniki w usuniętym drzewie binarnym z wyjątkiem korzenia były bezpieczne. Aby wskaźnik był bezpieczny, musimy ustawić go na 0. Nie mogłem zrobić funkcji, która usuwa drzewo (zachowując tylko korzeń), aby zaakceptować ref do wskaźnika, ponieważ używam korzenia (tego wskaźnika) jako pierwszego wejścia, aby przejść w lewo i w prawo.

void BinTree::safe_tree(BinTree * &vertex ) {
    if ( vertex!=0 ) {  // base case
        safe_tree(vertex->left);    // left subtree.
            safe_tree(vertex->right);   //  right subtree.
          // delete vertex;  // using this delete causes an error, since they were deleted on the fly using inorder_LVR. If inorder_LVR does not perform delete to the nodes, then, use delete vertex;
        vertex=0;  // making a safe pointer
    }
} // end in

Podsumowując, odniesienie do wskaźnika jest nieprawidłowe, gdy parametr formalny jest (tym) wskaźnikiem.

 1
Author: Mohd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-24 00:49:57

Witamy w C++11 i rvalue referencji:

#include <cassert>
#include <string>

using std::string;

void myfunc(string*&& val)
{
    assert(&val);
    assert(val);
    assert(val->c_str());
    // Do stuff to the string pointer
}

// sometime later 
int main () {
    // ...
    string s;
    myfunc(&s);
    // ...
}

Teraz masz dostęp do wartości wskaźnika (o którym mowa przez val), który jest adresem łańcucha znaków.

Możesz zmodyfikować wskaźnik i nikogo to nie obchodzi. Jest to jeden z aspektów tego, co rvalue jest na pierwszym miejscu.

Bądź ostrożny: wartość wskaźnika jest ważna tylko do powrotu myfunc(). W końcu to tymczasowe.

 0
Author: not-a-user,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-01 13:51:40

Wiem, że możliwe jest przekazywanie odniesień do wskaźników, zrobiłem to w zeszłym tygodniu, ale nie pamiętam, jaka była składnia, ponieważ twój kod wygląda teraz poprawnie dla mojego mózgu. Jednak inną opcją jest użycie pointers of pointers:

Myfunc(String** s)
 -1
Author: Robert Gould,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-05 05:15:56

Myfunc ("string*& val") to samo nie ma sensu. "string * & val" oznacza "string val", * i & anuluje się. W końcu nie można pasować zmiennej łańcuchowej do funkcji ("string val"). Tylko podstawowe typy danych mogą być przekazywane do funkcji, dla innych typów danych muszą być przekazywane jako wskaźnik lub odniesienie. Możesz mieć ciąg& val lub ciąg* val do funkcji.

 -8
Author: Shashikiran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-05 08:23:56