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

Jak zdefiniować wewnątrz funkcji zmienną, która będzie "zapamiętana"?

VPS Starter Arubacloud
+1 głos
328 wizyt
pytanie zadane 26 grudnia 2018 w C i C++ przez donekdzwonek Początkujący (420 p.)
#include <iostream>

using namespace std;

int liczba, suma;

void Dodaj( int liczba)
{
    int suma = suma + liczba;

    cout<<suma<<endl;

}

int main()
{
    Dodaj(1);
    Dodaj(2);
    Dodaj(3);
    Dodaj(4);
    Dodaj(5);
    return 0;
}

Mógłbym przekazać sumę przez referencję, ale wolałbym zrobić zmienną int suma jako lokalną. Jak zrobić to tak, żeby wartość zmiennej suma była zapamiętana pomiędzy wywołaniem każdej z funkcji?

4 odpowiedzi

+1 głos
odpowiedź 26 grudnia 2018 przez mokrowski Mędrzec (155,460 p.)

Nie ma co demonizować tego static. Oprócz tego że rzeczywiście utrudnia testy (trzeba przygotować kontrolowane setUp(...), nie popadajmy w fanatyzm "wszystko ma być immutable a funkcje pure i total".

Przy pierwszym wejściu do funkcji zmienna static od C++11 jest inicjalizowana atomowo (czyli nie zaszkodzi inicjalizacji także wielowątkowość). Oczywiście jeśli ma być bezpieczne wielowątkowo, kod dodatkowo należy przemyśleć bo dodawanie nie jest atomowe. Ale pewnie to nie ten poziom rozważań.

Zmienna statyczna inicjalizowana jest w C++ przy pierwszym wejściu do funkcji jawnie zerem. Dalsze wykonania pomijają tę inicjalizację. Zmieniłem także nazwę na IMHO sensowniejszą:

#include <iostream>
 
using namespace std;
 
void wyswietl_skumulowane( int liczba)
{
    static int suma = 0;
    suma += liczba;
 
    cout << suma << endl;
}
 
int main()
{
    wyswietl_skumulowane(1);
    wyswietl_skumulowane(2);
    wyswietl_skumulowane(3);
    wyswietl_skumulowane(4);
    wyswietl_skumulowane(5);
    wyswietl_skumulowane(-15);
}

 

komentarz 27 grudnia 2018 przez Aisekai Nałogowiec (42,190 p.)
edycja 27 grudnia 2018 przez Aisekai

Ale w tym przypadku, to użycie static, żeby przechowywać informacje o jakiejś nieglobalnej informacji, jest najgorszym możliwym sposobem. Już dużo lepiej (bezpieczniej, umożliwiając jakiekolwiek skalowanie aplikacji) jest zamknąć to jako właściwość danego obiektu i tam inkrementować. Kolejna sprawa dodatkowo doprowadza to do niekontrolowanych zachowań, wynikłych z powodu niekontrolowania tej zmiennej (w każdym miejscu można zmienić jej wartość). Mniej ważną kwestią jest to, że wprowadzenie takich zmiennych może narazić na konflikt w nazewnictwie.

Dodatkowo łamie to jedną z ważnych zasad:

  • Powtarzalność: Testy powinny być powtarzalne na każdym środowisku. Testy nie mogą mieć stanów początkowych, ani zasobów do wyczyszczenia. Oznacza to także brak zależności w stosunku do zasobów zewnętrznych (baza danych, system plików, itd.)

I wymaga od osoby testującej, znajomości działania danej metody/funkcji oraz czyszczenia za każdym razem tego statycznego pola, zamiast w każdym teście tworzyć sobie nowe obiekty których testujesz jakieś metody. Dodatkowo, twoja funkcja łamie kolejną zasadę - SP. Po pierwsze, zwiększa jakąś tam zmienną, a po drugie wyświetla jej wartość. Nazwa nie jest sensowniejsza, tak samo jak parametry. Gdybyś dostał tylko nagłówek: 

void wyswietl_skumulowane( int liczba)

to co oznacza ta liczba? Bo według mnie, ile razy ma zostać wyświetlona zmienna skumulowane. Dopiero po przeglądnięciu kodu funkcji, dowiaduję się że tą liczbę dodaję do jakiejś innej zmiennej.

Kolejna rzecz: debugowanie czegoś takiego jest mocno utrudnione - nigdy nie wiesz w którym miejscu mogła zostać zmieniona wartość tej zmiennej.

nie popadajmy w fanatyzm "wszystko ma być immutable a funkcje pure i total".

Nie ma być, ale powinno być. Wujek Bob kiedyś napisał, że kod jest dla człowieka, a tylko od czasu do czasu jest odpalany (czy coś w ten deseń). 

Edit: Wystarczy sobie zadać proste pytanie: wolałbyś pracować z "czystym" kodem czy kodem spaghetti?

komentarz 27 grudnia 2018 przez mokrowski Mędrzec (155,460 p.)

Kolega tylko nie wiedział jak działa static.... :-) Na pytanie czy wolę pracować z kodem spagetti czy czystym odpowiadam zawsze że wolę pracować z rozsądnymi ludźmi :) A i nie takie funkcje da się mockować i obsłużyć stan. To przykład składni a nie aplikacja opracowana zgodnie z wykładniami TDD, BDT, DDD, czy S.O.L.I.D. , YAGNI, DRY, GRASP (resztę wpisz sam... )

BTW jeśli pytanie było o klasę pamięci static, to nie sądzę by te światłe skróty pytający mógł zrozumieć od pierwszego przykładu.

Ogólnie tak, zgadzam się... są zasady jazdy rowerem i zachowania optymalnej kadencji na długich odcinkach ale tu odczepiono właśnie 2 kółka pomocnicze od roweru :)

0 głosów
odpowiedź 26 grudnia 2018 przez hun1er76 Stary wyjadacz (11,960 p.)

Zmienna lokalna może być widoczna tylko w bloku, w którym została zadeklarowana. Dowiedz się co to są zmienne globalne i lokalne oraz poczytaj sobie o zasięgu zmiennych

np. https://pl.wikibooks.org/wiki/C/Zmienne#Zasi%C4%99g_zmiennej

2
komentarz 26 grudnia 2018 przez donekdzwonek Początkujący (420 p.)
A co ze zmiennymi static?
0 głosów
odpowiedź 26 grudnia 2018 przez Aisekai Nałogowiec (42,190 p.)
Nie korzystaj ze zmiennych globalnych (tam gdzie to mozliwe). W twoim przypadku wystarczy zmienić typ funkcji na double, która przyjmuje 2 parametry i zwraca ich sume. W mainie możesz sobie tworzyć zmienne lokalnie.
1
komentarz 26 grudnia 2018 przez donekdzwonek Początkujący (420 p.)
A co ze zmiennymi static?
komentarz 26 grudnia 2018 przez Aisekai Nałogowiec (42,190 p.)
Powiem tak. To zależy, do czego Ci jest to potrzebne i co ma to reprezentować. Musiałbym znać większy zarys problemu.
komentarz 26 grudnia 2018 przez Munvik Dyskutant (9,350 p.)
Aisekai dlaczego zmienna statyczna jest gorsza w tym przypadku od przesłania sumy jako referencje ?
1
komentarz 26 grudnia 2018 przez Aisekai Nałogowiec (42,190 p.)
Jeżeli javowy static ~ c++ static to:

1. Brak możliwości rozszerzania projektu - jeżeli chciałbyś równolegle móc "dodawać" do dwóch różnych zmiennych to nie masz takiej możliwości

2. W każdym miejscu, w którym jest dostęp do tej zmiennej statycznej, jest możliwość niechcianego zmodyfikowania jej. Tracisz nad tym kontrolę.

3. Utrudnione testowanie - jeden test może wpływać na inny test, co jest niepoprawna praktyka ( https://www.google.com/amp/s/dariuszwozniak.net/2013/11/18/kurs-tdd-czesc-6-dobre-i-zle-praktyki-testow-jednostkowych/amp/ punkt z Zasadami pisania testow jednostkowych) czy też immutability.

4. Bardziej intuicyjne, przynajmniej dla mnie, jest to, ze funkcja Dodaj() powinna przyjmowac dwa parametry i zwracać ich sumę.

Przy czym, nie mówię tutaj tylko o tym przypadku, ale ogólnie. Duzo też zależy od tego, co ta funkcja będzie zwiekszala.
1
komentarz 26 grudnia 2018 przez Aisekai Nałogowiec (42,190 p.)
Jeszcze jedna rzecz. Nie musi to być przez referencję, imo nawet lepiej byłoby przez wartosc zgodnie z inną zasadą, że jeżeli funkcja coś zwraca to nie powinna modyfikować parametrow (przesłanie przez referencję umozliwia ich modyfikację). Jedyne funkcje które powinny modyfikować parametry to typu void ().
komentarz 27 grudnia 2018 przez Munvik Dyskutant (9,350 p.)
Jasne, moja koncepcja właśnie opierała się na void ale zgadzam się, lepiej zeby zwracała wartość.
0 głosów
odpowiedź 26 grudnia 2018 przez coderCpp93 Gaduła (4,200 p.)
Ja bym zmienił funkcję Dodaj na typ int, która zwracała by tą sumę. A w funkcji main wywołał bym tą funkcję i zapisał to co by zwracała w zmiennej. Jeśli chodzi o static to, o ile mi wiadomo jest to zdeprecjonowane, ale możesz to użyć. W Javie static oznacza, że metoda lub zmienna nie należy do klasy, w której się znajduje, w C++ też. Możesz w zmiennej statycznej zapisać wartość sumy, i ilekroć wywołasz funkcję ta zmienna będzie nadpisywana.
komentarz 27 grudnia 2018 przez mokrowski Mędrzec (155,460 p.)
static "zdeprecjonowane" ? A co to znaczy?

Podobne pytania

0 głosów
1 odpowiedź 382 wizyt
0 głosów
1 odpowiedź 386 wizyt
0 głosów
3 odpowiedzi 611 wizyt
pytanie zadane 26 stycznia 2018 w C i C++ przez Hiskiel Pasjonat (22,830 p.)

92,453 zapytań

141,262 odpowiedzi

319,088 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!

...