• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Wskaźniki i referencje razem. Czy to co robię jest bezpieczne?

VPS Starter Arubacloud
0 głosów
202 wizyt
pytanie zadane 22 marca 2018 w Offtop przez Marcin Siniarski Gaduła (4,420 p.)

Postanowiłem pobawić się z wskaźnikami i referencjami naraz. Jak na razie wszystko jest dobrze, jednak chce się dowiedzieć trochę więcej.
Aktualnie eksperymentuje razem z klasami.

Oto dotychczasowy rezultat:

#include <iostream>

template<typename T>
class Vector{
  public:
  Vector(T init_x, T init_y, T init_z)
    :x(init_x),y(init_y),z(init_z){

  }
  T getX(){return x;}
  T getY(){return y;}
  T getZ(){return z;}
  void setX(T newX){this->x=newX;}
  void setY(T newY){this->y=newY;}
  void setZ(T newZ){this->z=newZ;}
  private:
  T x,y,z;
};

template <typename T> void referencePtr(T *&ptrRef);

int main(int argc, char* argv[]){
  Vector<int>* vct = new Vector<int>(0,0,0);
  int *z = new int(vct->getZ());
  referencePtr(z);
  vct->setZ(*z);
  std::cout << vct->getZ() << std::endl;
  std::cin.get();
  delete z;
  delete vct;
  return 0;
}
template <typename T> void referencePtr(T *&ptrRef){
  *ptrRef += 1;
}

 

1 odpowiedź

+2 głosów
odpowiedź 22 marca 2018 przez Sebastian Fojcik Nałogowiec (43,020 p.)
wybrane 23 marca 2018 przez Marcin Siniarski
 
Najlepsza

Wszystko jest w jak najlepszym porządku. Jak przesyłasz wskaźnik do funkcji, to oczywiście domyślnie wskaźnik przekazywany jest przez wartość (sam wskaźnik jako zmienna zajmuje miejsce w pamięci). U Ciebie z tego co widzę funkcja (a w zasadzie jej szablon) przyjmuje referencję do wskaźnika. Czyli nie tworzysz na stosie nowego wskaźnika.

Jednak w przypadku Twojej funkcji, ta referencja nie ma wpływu na nic innego. Tak samo zadziała program bez referencji. Przesyłanie wskaźnika przez referencje umożliwia to, aby w funkcji przestawić ten wskaźnik na coś innego (albo przyspieszyć nieco wywołanie funkcji). Czyli w swojej funkcji mógłbyś np. zarezerwować nową pamięć na wskaźnik podany jako argument wywołania, a tę obecnie zarezerwowaną zwolnić. Wtedy przesłanie wskaźnika w referencji byłoby konieczne.

Musisz też być świadomy konsekwencji przesyłania, już nawet nie wskaźnika, ale czegokolwiek przez referencję. Spójrz na poniższy kod:

void f( int * &wsk )
{
	*wsk += 1;
}

int main()
{
	int n = 5;
	int * wsk = &n;
	cout << *wsk << endl; // 5
	f( wsk );
	cout << *wsk << endl; // 6

	return 0;
}

Rezultat oczywiście do przewidzenia. Ale popatrz co jest niemożliwe przez to, że funkcja przyjmuje referencję:

void f( int * &wsk )
{
	*wsk += 1;
}

int main()
{
	int n = 5;
	int * wsk = &n;
	cout << *wsk << endl; // 5
	f( &n );    // BŁĄD !!!
	cout << *wsk << endl;

	return 0;
}

Gdyby funkcja przyjmowała zwykły wskaźnik, a nie referencję do niego, to wywołanie &n byłoby możliwe. W tym przypadku odbierasz sobie to prawo.

void f( int * wsk )
{
	*wsk += 1;
}

int main()
{
	int n = 5;
	int * wsk = &n;
	cout << *wsk << endl; // 5
	f( &n );    // OK
	cout << *wsk << endl; // 6

	return 0;
}

Jeśli miałbym skomentować to, co wyprawiasz wewnątrz main. Cóż, ciężko coś sensownego skomentować, bo widać, że kod, który wysłałeś jest mocno dydaktyczny. W sensie: żaden programista nie pisałby tego wszystkiego, aby zwiększyć współrzędną z o jeden :-P
Aczkolwiek kod jest poprawny, tylko bardzo dziwnie i ryzykownie napisany. Np. tworzysz dynamicznie zmienną:

int *z = new int(vct->getZ());

Tylko po to, aby ją zwiększyć o jeden, nadpisać przy jej pomocy współrzędną z i skasować.
Jakbyś nie mógł napisać czegoś takiego:

vct->setZ( vct->getZ()+1 );

Ale nie czepiam się. Rozumiem, że Twój przykład jest tylko dydaktyczny ;-)

Jak tak teraz patrzę, to nie zadałeś nawet konkretnego pytania, więc mam tylko nadzieję, że udzieliłem choć trochę oczekiwanej odpowiedzi :-)

komentarz 23 marca 2018 przez Marcin Siniarski Gaduła (4,420 p.)

Wiem, moje użycie wskaźnika *z jest praktycznie bezcelowe, lecz funkcja oczekuje wskaźnika, a nie liczby lub obiektu.

 

Rezultat oczywiście do przewidzenia. Ale popatrz co jest niemożliwe przez to, że funkcja przyjmuje referencję:
[...]
 f( &n );    // BŁĄD !!!

 To akurat wiem. Referencja sama pobiera adres liczby dlatego jest błąd. C++ musi wiedzieć (uwaga, tak sobie wyjaśniam jak działają referencje) gdzie dopisać drugą nazwę do adresu zmiennej.

Dziękuję za wyjaśnienie oraz rozpisanie się na ten temat :-)

Podobne pytania

0 głosów
0 odpowiedzi 161 wizyt
pytanie zadane 15 marca 2016 w C i C++ przez falauthy Stary wyjadacz (11,550 p.)
0 głosów
3 odpowiedzi 851 wizyt
pytanie zadane 18 lipca 2018 w C i C++ przez Nowacx02 Obywatel (1,060 p.)
0 głosów
1 odpowiedź 2,723 wizyt
pytanie zadane 4 marca 2018 w C i C++ przez bartez86 Nowicjusz (220 p.)

92,455 zapytań

141,263 odpowiedzi

319,100 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...