Zalecanie korzystania z kontenerów zamiast dynamicznej alokacji w C++

Odpowiedz Nowy wątek
2019-03-08 18:08
4

Sytuacja ta powtarza się na tym forum od lat:

  • Przychodzi nowicjusz, mający wyraźne problemy z podstawami C++, i prezentuje swój kod upstrzony rozmaitymi new, delete, malloc, tab[i], *(ptr+n), tablic znaków, itd, itp.
  • Informuje się go, że to jest zła praktyka w C++ i ma zamiast tego korzystać z, niepotrzebne skreślić: std::vector, std::string, unique_ptr, shared_ptr, etc, etc.

Sytuacja ta wynika z faktu, że programy nauczania w szkołach, a być może (nie wiem) także na niektórych uczelniach, notorycznie:

  • Wymagają od uczniów / studentów znajomości programowania imperatywnego na poziomie C, a zatem w szczególności: dynamicznej alokacji, tablic, arytmetyki wskaźników;
  • Jednocześnie nauczają tego w C++, ponieważ:
    • C++ udostępnia struktury, które są w wielu miejscach wygodniejsze w użyciu, aniżeli C (np. łatwiej jest nauczyć kogoś korzystania z std::cout aniżeli printf);
    • Kiedy już nauczy się tablic, można wprowadzić klasy, w tym kontenery bez konieczności zmiany języka.

Innymi słowy: Chcąc / musząc nauczyć dynamicznej alokacji, wybierają do tego takie narzędzie, które po pierwsze to umożliwia, po drugie jest stosunkowo najwygodniejsze spośród tych, które to umożliwiają.

Z jednej strony rozumiem forumowiczów, których bije po oczach to, co z ich perspektywy jest "nauczaniem złych praktyk w C++". Z drugiej strony - choć to zabrzmi pewnie jak herezja - rozumiem także nauczycieli, którzy chcą przerobić wymagany materiał bez dodatkowych utrudnień, rozpraszających uwagę ucznia od tej konkretnie wiedzy, którą chcą mu wbić do głowy.

NIE rozumiem natomiast radzenia takim nowicjuszom, by zaczęli używać kontenerów / unique_ptr / etc zamiast operowania na czystych, dynamicznie zaalokowanych wskaźnikach! Jeśli - zgodnie z tymi radami - przestaną uczyć się dynamicznej alokacji itp, to nie wykażą się wiedzą, której się od nich wymaga. Czy nam się to podoba, czy nie: Jeśli każe się im używać new, delete, itp, to muszą nauczyć się tego używać.

Oczywiście, można radzić im np. pisać w C a nie w C++, skoro już muszą operować na "czystych", dynamicznie zaalokowanych wskaźnikach. Jednak:

  • W zasadzie nawet i to rodzi podobne wątpliwości, no bo w C są VLA, więc czy dobrą praktyką jest stosowanie dynamicznych alokacji zamiast VLA?
    • Ale idąc tym tropem: Jak w ogóle można nauczyć kogoś dynamicznej alokacji, jednocześnie nie ucząc go mitycznych "złych praktyk" ani nie rozpraszając jego uwagi zadaniem na tyle skomplikowanym, by VLA nie mogło się sprawdzić?
  • Moim zdaniem, pisanie w C zamiast w C++ przez takiego ucznia to byłoby już, z jego perspektywy, byciem plus catholique que le pape...

Jak można mu wytłumaczyć, dlaczego pisanie *(ptr+offset) ma się jednocześnie wykluczyć z pisaniem cout << wynik << endl, a wymuszać pisanie printf("%d\n", wynik) - ah uwaga na pomyłki jeśli wynik jest long long a nie int

A zresztą, w zasadzie po co? Bo mistyczna "jakość kodu"? Jednak tu jest jakieś przemieszanie, ponieważ żeby wiedzieć, jak należy pisać kod, żeby był elegancki, "wysokiej jakości", żeby wbić komuś do głowy wszystkie patterny, antipatterny, itp, to trzeba najpierw nauczyć go, czym w ogóle jest programowanie i jak ma pisać kod, żeby w ogóle działał!

To, do czego - moim zdaniem - można rzeczywiście przyczepić się programom nauczania, to to, że zaczynają od nauczania programowania na poziomie C. Jakiś doświadczony programista mi kiedyś w cztery oczy powiedział, że uważa to za pomyłkę, i że należy zaczynać od C# albo Javy - a na inne wynalazki, w tym C czy C++, przyjdzie czas później - żaden z tych dwóch języków nie nadaje się dla początkujących. Rozumiem ten punkt widzenia; jednak wyrzucenie arytmetyki wskaźników i dynamicznej alokacji z programów nauczania dla liceum to chyba marzenie ściętej głowy.

Póki zatem tak się nie stanie, proponuję przestać wreszcie czepiać się nowicjuszy, potrzebujących pomocy z materiałem, którego wymaga od nich szkoła.

@kmph: kojarzysz jakies dobre darmowe materialy jak teraz nalezy pisac w C++ ? Ja np. uczylem sie wieki temu z tego i pozniej jezyk poszedl w odstawke wiec moze warto byloby sobie odswiezyc: http://www.leinad.master.pl/ftp/programowanie/C++/C++%20(kurs)/ - WhiteLightning 2019-03-12 10:11

Pozostało 580 znaków

2019-03-08 19:31
0

TL;DR

kmph napisał(a):

Póki zatem tak się nie stanie, proponuję przestać wreszcie czepiać się nowicjuszy, potrzebujących pomocy z materiałem, którego wymaga od nich szkoła.

Dokładnie, ciągle w komentarzach zwracam na to uwagę odpowiadającym. Niektórzy nie rozumieją, że mus to mus.


Pozostało 580 znaków

2019-03-11 13:17
0
kmph napisał(a):
  • W zasadzie nawet i to rodzi podobne wątpliwości, no bo w C są VLA, więc czy dobrą praktyką jest stosowanie dynamicznych alokacji zamiast VLA?

VLA są na stosie, który jest ograniczony rozmiarowo (do np. 1 MB) i czasowo (nie możemy zwrócić wskaźnika do VLA, bo tablica zostanie zniszczona).
Jestem zwolennikiem VLA, ale ich przydatność jest ograniczona.

Pozostało 580 znaków

2019-03-11 19:35
0
Azarien napisał(a):

VLA są na stosie, który jest ograniczony rozmiarowo (do np. 1 MB) i czasowo (nie możemy zwrócić wskaźnika do VLA, bo tablica zostanie zniszczona).
Jestem zwolennikiem VLA, ale ich przydatność jest ograniczona.

Tak oczywiście, ale sformułowanie zadania w ten sposób, by w C nie dało się go zrobić na VLA skomplikuje to zadanie i odwróci uwagę od jego rzeczywistej treści, czyli dynamicznej alokacji. Tymczasem, AFAIK, dobrą praktyką pedagogiczną jest, by wprowadzając jakiś temat (np. dynamiczną alokację) zacząć od zadań TYLKO na dynamiczną alokację, bez dodatkowych trudności. A z kolei, na podstawie krytykowanego przeze mnie rozumowania, które widzimy często na forum, to takiego zadania pewnie NIE NALEŻAŁOBY rozwiązać poprzez dynamiczną alokację, a poprzez zastosowanie VLA, bo to lepsza praktyka.

Mamy więc sytuację, w której praktycznie nie da się sformułować treści zadania tak, by zastosowanie w rozwiązaniu dynamicznej alokacji było poprawne.

Pozostało 580 znaków

2019-03-11 21:51
2
kmph napisał(a):

Mamy więc sytuację, w której praktycznie nie da się sformułować treści zadania tak, by zastosowanie w rozwiązaniu dynamicznej alokacji było poprawne.

Wracając do C++, typowym zadaniem (albo ćwiczeniem) jest by napisać klasę, która dynamicznie alokuje obszar pamięci, zwalnia go w destruktorze, i kopiuje kiedy trzeba.
Ale rozwiązanie zaraz zostanie skrytykowane że teraz to przecież nie rule of 3, tylko rule of 5, a tak naprawdę to smartpointery i rule of 0, a w ogóle to wszystko powinno być template'em.

(to ostatnie mnie szczególnie irytuje - często przykłady jak coś zrobić są zaciemnione przez to że wszystko jest stemplejtowane, choć template'y zupełnie nie są przedmiotem rozważań)

edytowany 1x, ostatnio: Azarien, 2019-03-11 21:52

Pozostało 580 znaków

2019-03-12 09:35
kq
7

Silnie się nie zgadzam, i nie podoba mi się wyrażona w poście implikacja celowej złośliwości.

Z mojej perspektywy sytuacja wygląda tak:

Przychodzi nowicjusz z kodem naszpikowanym złymi praktykami, który jest nieczytelny, trudny do modyfikacji/utrzymania i, w ogólnym rozrachunku, sprawia, że postawione zadanie jest trudniejsze. Nie ma żadnego dowodu na to, że:

  • jest studentem, a nie samoukiem, który trafił na kurs
  • jeśli jest studentem, to na jego uczelni nie wolno uczyć się samodzielnie
    • a na egzaminie jest wymagane rozwiązanie z tablicy, bo inne nie zostanie uznane

Taki nowicjusz dostaje poradę, aby zaczął programować biorąc pod uwagę, że jest get_current_year(), a nie 1995, nie korzystał z błędnych poradników/tutoriali itd. Tutaj warto podkreślić, że rzadko jest to całość porady. Jeśli podany kod nie nadaje się na kandydata na IOCCC, lub ma porządne MCVE, to dostaje również bezpośrednie pytanie zadane w poście.

W mojej subiektywnej opinii (nie prowadziłem statystyk, więc mogę się mylić) mniej niż 50% odpowiada "ale na studiach tak karzo". Jeśli jednak już tak się stanie, to nikt im głowy nie urywa.


Na to, że program uczelni (albo kursów, tutoriali, książek) bywa beznadziejny nie jesteśmy w stanie wiele poradzić, ale nie ma absolutnie nic złego w informowaniu newbów, że istnieją lepsze rozwiązania niż używane przez nich obecnie. Przez podejście z pierwszego posta potem tacy "programiści" we własnych programach, albo już w pracy zawodowej, piszą własną implementację wektora (albo lepiej, listy), bo nikt im nawet nie wspomniał o tym, że w bibliotece standardowej jest już poprawna implementacja. Albo brzydzą się C++, bo jedyne co o nim wiedzą to mnóstwo new, delete i crashy spowodowanych błędnym ich użyciem.

Utrzymywanie ludzi w ignorancji, bo być może nie będą mogli natychmiastowo użyć nowej wiedzy, uważam za jednoznacznie szkodliwe.


edytowany 1x, ostatnio: kq, 2019-03-12 09:37

Pozostało 580 znaków

2019-03-12 10:12
1

Szkoły i uczelnie często nie rozróżniają C od C++, ponieważ tak łatwiej.
Ale to nie znaczy że uczniowie tak muszą pisać.
Nikt nikomu na uczelni nie zwróci uwagi i nie obniży oceny jeśli zamiast printf użyje w C++ cout.
Dbanie o rozdzielność tych dwóch języków jest pożyteczna, ponieważ edukuje ludzi nie tylko początkujących ale także wszystkich którzy to czytają.
Można się czepiać stylu w jakim się zwraca uwagę, ale są ludzie i ludziska.
Aktualnie C++ przeżywa dynamiczny rozwój i często nawet konsultanci tego języka nie są do końca zgodni co jest lepsze.
Od tego jest forum żeby takie poglądy wymieniać.

Moderatorem forum C++ jest @kq, którego uważam za jedną najbardziej wyważonych osobę na forum, więc czepiać się można ew. ludzi, którzy
niedawno dołączyli i próbują budować swoje ego kosztem innych. I takie zachowania trzeba potępiać niezależnie od języka.


Szacuje się, że w Polsce brakuje 50 tys. programistów
zwróci uwagę i może obniżyć jeżeli student w ogóle nie ogrania kodu który oddaje udając że sam napisał - Miang 2019-03-14 10:18

Pozostało 580 znaków

2019-03-12 15:31
2

Rozwiązanie tego problemu jest proste – odpowiedzieć na temat, sugerując wykonanie w taki sposób, którego oczekują nauczyciele/prowadzący. Natomiast dodatkowo i wyraźnie poinformować o bolączkach danego rozwiązania, wyjaśnić dlaczego jest złe i jak rozwiązanie powinno wyglądać, jeśli chodzi o współczesne standardy tworzenia kodu. Wilk syty i owca cała.

Użytkownicy przebywający tutaj znaczną ilość czasu potrafią wyłapać uczniaków bez dopytywania, natomiast masa w miarę nowych użytkowników tego nie potrafi i na siłę forsuje swoje pomysły, jednocześnie nie przyjmując do wiadomości, że nie za bardzo pomaga.


edytowany 1x, ostatnio: furious programming, 2019-03-12 15:32

Pozostało 580 znaków

2019-03-12 19:03
0

@kq:

Ale w tym momencie wracamy do punktu wyjścia: Przy prezentowanym przez Ciebie podejściu nie ma praktycznej możliwości zrobienia zadania edukacyjnego na dynamiczną alokację, gdyż albo będzie to zadanie na multum innych rzeczy oprócz dynamicznej alokacji, albo uznasz, że dynamiczna alokacja jest nieprawidłowym rozwiązaniem!

Oczywiście, że istnieje std::vector i bezwzględnie należy o jego istnieniu poinformować.

Ale idąc tym tropem: Oczywiście istnieje także std::sort, a nawet bibliotece standardowej C mamy qsort - jednak ich istnienie nie oznacza, że nie można dać zadania napisz własne sortowanie. A przecież idąc tym tropem można uznać, że rozwiązanie zadania napisz własne sortowanie poprzez wklepanie mergesorta, quicksorta, a na jeszcze wcześniejszych etapach nauki nawet bubblesorta jest nieprawidłowe, bo należy użyć sortowania z biblioteki standardowej.

Oczywiście, że kod pisany przez licealistów nie będzie nadawał się na produkcję. Bo też i nadawać się nie może! Nie da się od razu nauczyć delikwenta tyle, by pisał kod nadający się na produkcję! Dlatego też zaczynamy od zadań sztucznych i dopuszczamy rozwiązania sztuczne.

Tym samym rozumowaniem można zabraniać uczyć absolutnego newbiego pisania pętli. Przecież nawet C++ ma #include <algorithm>, o wynalazkach rodem z nowszych języków takich jak LINQ w C# już nie wspominając. Ich należy używać zamiast pisania pętli od ręki! A jednak słusznie zaczyna się programowanie od trywialnych pętli na tablicach.

Pozostało 580 znaków

2019-03-14 13:41
1

Jeśli student czy nawet samouczeń nie przećwiczy dynamicznej alokacji polegając tylko na kontenerach, to nigdy nie będzie jej umiał a działanie takiego std::vector pozostanie dla niego magią.

Pozostało 580 znaków

2019-03-14 16:11
kq
2
kmph napisał(a):

Ale w tym momencie wracamy do punktu wyjścia: Przy prezentowanym przez Ciebie podejściu nie ma praktycznej możliwości zrobienia zadania edukacyjnego na dynamiczną alokację, gdyż albo będzie to zadanie na multum innych rzeczy oprócz dynamicznej alokacji, albo uznasz, że dynamiczna alokacja jest nieprawidłowym rozwiązaniem!

Musisz mieć na myśli jakieś bardzo dziwne rozwiązania, bo zadanie typu "napisz własną implementację dynamicznej tablicy/listy [12]-kierunkowej" jest jak najbardziej sensowne z mojej perspektywy. Przynajmniej jeśli chodzi o naukę struktur danych, bo na pewno nie w kursie podstaw C++.

Ale idąc tym tropem: Oczywiście istnieje także std::sort, a nawet bibliotece standardowej C mamy qsort - jednak ich istnienie nie oznacza, że nie można dać zadania napisz własne sortowanie. A przecież idąc tym tropem można uznać, że rozwiązanie zadania napisz własne sortowanie poprzez wklepanie mergesorta, quicksorta, a na jeszcze wcześniejszych etapach nauki nawet bubblesorta jest nieprawidłowe, bo należy użyć sortowania z biblioteki standardowej.

Idąc tym tropem: uczymy się tutaj języka, czy podstaw programowania/algorytmiki/struktur danych? Przez takie mieszanie pojęć później mamy kod produkcyjny z bubblesortem, bo niedouczony programista nie wiedział, że jest std::sort. Np. w Pythonie coś takiego się nie zdarza, bo nikt o zdrowych zmysłach nie uczy bubblesorta w tym języku, a nawet jeśli - to nie przed użyciem sorted z biblioteki standardowej.

Oczywiście, że kod pisany przez licealistów nie będzie nadawał się na produkcję. Bo też i nadawać się nie może! Nie da się od razu nauczyć delikwenta tyle, by pisał kod nadający się na produkcję! Dlatego też zaczynamy od zadań sztucznych i dopuszczamy rozwiązania sztuczne.

Co nie oznacza, że powinniśmy celowo upośledzać ich naukę poprzez naukę złych praktyk. Kursu jazdy samochodem nie zaczynasz od budowy 18-wiecznego silnika parowego. Dlaczego chcesz zaczynać kurs C++ od nauki korzystania z przestarzałych i zbędnych (a czasem nawet po prostu błędnych) rozwiązań?

Tym samym rozumowaniem można zabraniać uczyć absolutnego newbiego pisania pętli. Przecież nawet C++ ma #include <algorithm>, o wynalazkach rodem z nowszych języków takich jak LINQ w C# już nie wspominając. Ich należy używać zamiast pisania pętli od ręki! A jednak słusznie zaczyna się programowanie od trywialnych pętli na tablicach.

Brak mi danych eksperymentalnych, aby oceniać czy rzeczywiście tak słusznie.

Azarien napisał(a):

Jeśli student czy nawet samouczeń nie przećwiczy dynamicznej alokacji polegając tylko na kontenerach, to nigdy nie będzie jej umiał a działanie takiego std::vector pozostanie dla niego magią.

Nie uważam, aby taka wiedza była początkującym niezbędna.


Ta prelekcja generalnie podsumowuje to co mówię:


Ciekawe jakie są statystyki C vs C++ na 8 bitowe atmegi (tak popularne w Arduino) i jak to się ma do "stop teaching C". - Marooned 2019-03-25 12:03
Nie wiem, stawiam na znaczącą (ale stale zmniejszającą się) przewagę C. Przy czym tytuł prelekcji trzeba brać w jej kontekście - jej treść można sprowadzić do "jeśli uczysz C++, to nie zaczynaj od nauki C, tylko ucz C++ od razu" - kq 2019-03-25 12:13

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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