• 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"?

+1 głos
131 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

+2 głosów
odpowiedź 26 grudnia 2018 przez mokrowski VIP (108,060 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 (36,150 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 VIP (108,060 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 Dyskutant (9,490 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 (36,150 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 (36,150 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 (8,290 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 (36,150 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 (36,150 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 (8,290 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 (3,890 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 VIP (108,060 p.)
static "zdeprecjonowane" ? A co to znaczy?

Podobne pytania

0 głosów
3 odpowiedzi 155 wizyt
pytanie zadane 26 stycznia 2018 w C i C++ przez Hiskiel Pasjonat (22,990 p.)
0 głosów
1 odpowiedź 81 wizyt
Porady nie od parady
Zadając pytanie postaraj się o odpowiedni tytuł, kategorię oraz tagi.Tagi

64,898 zapytań

111,368 odpowiedzi

234,329 komentarzy

46,744 pasjonatów

Przeglądających: 194
Pasjonatów: 9 Gości: 185

Motyw:

Akcja Pajacyk

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

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...