Funkcja zwracająca rezultat będący referencją l-wartości.

0

Przebijam się przez Opus Magnum C++, książka Pana Jerzego Grębosza jest bardzo fajna ale potrafi zamotać próbami łatwych wyjaśnień.

Temat: funkcja zwracająca rezultat będący referencją l-wartością zostawił u mnie niedosyt.
Przepisałem przykład z książki i po części rozumiem.

#include <iostream>

using namespace std;

int globalny_jedynkowy = 25;
int globalny_inny = 77;

int f_wartosc(int ktory) 
{
    int lokalny = 4;
    if (ktory == 1) return globalny_jedynkowy;
    else return globalny_inny;
} 
int & f_ref_lwartosci(int ktory) 
{
    int lokalny = 4;
    if (ktory == 1) return globalny_jedynkowy;
    else return globalny_inny;
}
void wypisz(string txt, int a) 
{
    cout << txt;
    if(a) cout << a << ", ";
    cout << "globalny_jedynkowy = " << globalny_jedynkowy << ", globalny_inny = " << globalny_inny << endl;
}

int main() 
{
    int n{0};

    n = f_wartosc(1);
    wypisz("f_wartosc(1) = ", n); // 25
    n = f_wartosc(6);
    wypisz("f_wartosc(6) = ", n); // 77

    cout << "\n";

    n = f_ref_lwartosci(1);
    wypisz("f_ref_lwartosci(1) = ", n); // 25
    n = f_ref_lwartosci(6);
    wypisz("f_ref_lwartosci(6) = ", n); // 77

    cout << "\n";

    n = f_ref_lwartosci(1) = 5000;
    wypisz("f_ref_lwartosci(1) ", 0);
    n = f_ref_lwartosci(6) = 8000;
    wypisz("f_ref_lwartosci(6) ", 0);

}

Nie potrafię jednak pojąć użyteczności tego aspektu użycia funkcji. Nie udało mi wymyśleć niczego praktycznego. Myślałem o równaniach drugiego stopnia, o programie, który szukałby pierwiastków (x1, x2) ale to chyba nie do tego.

Jaką wartość mogą mieć dla mnie te koncepcje języka C++ ? Nie spotkałem się z czymś podobnym w Javie, Pythonie czy JavaScript.

5

Na tym etapie ta technika faktycznie jawi się jako bezużyteczna. W praktyce stosuje się w sytuacjach kiedy albo chcemy udostępnić możliwość modyfikacji wewnętrznego stanu lub gdy zwracamy jakąś wartość z klasy/kontenera i chcemy dać użytkownikowi klasy/kontenera wybór czy chce zrobić kopię czy zadowoli się referencją.

Przykładowo operator[] z std::vector zwraca referencję, dzięki czemu możemy wykonać przypisanie

std::vector<int> ints {1,2,3};
ints[1] = 4;
// ints == {1,4,3}
2

Method chaining - jak masz metodę Foo& Foo::do_something() { /* ... */ return *this; } możesz sobie zrobić API, w którym wywołujesz metody jedna po drugiej obj.do_something().do_something_else().do_even_better(). Analogiczne do zwracania self na końcu metody w Pythonie. Patrz tutaj

1

Podaruje sobie komentowanie przykładu do którego treści nie znam.

Jaką wartość mogą mieć dla mnie te koncepcje języka C++ ? Nie spotkałem się z czymś podobnym w Javie, Pythonie czy JavaScript.

Ogólnie? Chodzi o to że mogą(nie musza) pomóc z wydajnością. Ale z r-value i l-value bywa tak że czasami coś będzie r-value a czasami l-value.
najlepsze wytłumaczenie tego masz tu(poczawszy od dedukcji typów po perfect forwarding)
https://helion.pl/ksiazki/skuteczny-nowoczesny-c-scott-meyers,e_1vj9.htm#format/e

za darmo
https://isocpp.org/blog/2016/04/quick-q-what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues
https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

edit:
aa chyba źle zrozumiałem twoje pytanie(myślałem że chodzi o lvaue i rvalue ogólnie) ale i tak polecę efficient c++.

5

Zwyczajnie zbyt zagmatwany przykład.

Ja to zazwyczaj tłumaczę na takim prostym przykładzie:

#include <iostream>
using namespace std;

unsigned long &lmin(unsigned long &a,unsigned long &b) { return a<b?a:b; }
unsigned long &lmax(unsigned long &a,unsigned long &b) { return a<b?b:a; }

unsigned long nwd(unsigned long a,unsigned long b)
{
	//while((a>0)&&(b>0)) lmax(a,b)-=lmin(a,b);
	while((cout<<a<<' '<<b<<endl)&&(a>0)&&(b>0)) lmax(a,b)-=lmin(a,b);
	return lmax(a,b);
}

int main()
{
	cout<<nwd(2*7*5,2*7*11)<<endl; // 2*7=14
	return 0;
}
3
Pangeon napisał(a):

Przepisałem przykład z książki i po części rozumiem.

offtopic: niepotrzebnie się męczyłeś troszkę googlania i wychodzi storna autora (brzydka, ale jest).
A tam jest link do zip z kodami źródłowymi przykładów z książki

2
MarekR22 napisał(a):
Pangeon napisał(a):

Przepisałem przykład z książki i po części rozumiem.

offtopic: niepotrzebnie się męczyłeś troszkę googlania i wychodzi storna autora (brzydka, ale jest).
A tam jest link do zip z kodami źródłowymi przykładów z książki

Ale przy przepisywaniu jednak dużo w głowie zostaje i więcej się rozumie -- więc przepisywanie to całkiem dobry sposób nauki. Inną sprawą jest jakość przykładu. Przykład jest trochę wydumany -- a żeby coś pokazać i pozwolić uczniowi zrozumieć, to wypadałoby dać jakiś przykład w miarę realny... Typowy przykład zwracania l-wartości pojawia się dopiero przy klasach -- jak pokazał @several.

0

A czy nie można uzyskać podobnego efektu w C++ zwracając np. wskaźnik do inta?
Czy może jednak to działa inaczej?

0
LukeJL napisał(a):

A czy nie można uzyskać podobnego efektu w C++ zwracając np. wskaźnik do inta?
Czy może jednak to działa inaczej?

Można, ale musiałbyś wołać *o = 12 zamiast o = 12 i obj->foo() zamiast obj.foo(). Poza tym wskaźnik może być pusty, referencję trochę trudniej zepsuć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1