Ljubavno pismo učenju
Krajem sedamdesetih godina računarski svet već je raspolagao jezicima koji su programerima pružali neposrednu kontrolu nad mašinom, kao i jezicima sposobnim da složene sisteme predstave kroz bogate i pregledne apstrakcije. Te dve snage retko su prebivale u istom alatu. Jezik C omogućavao je brzinu, prenosivost i precizno upravljanje memorijom, procesorom i operativnim sistemom, zbog čega je postao jedan od temelja sistemskog programiranja. Sa rastom programa, međutim, rasla je i teškoća njihovog održavanja: podaci i funkcije mogli su se rasuti kroz hiljade redova koda, unutrašnje stanje sistema ostajalo je izloženo nepažljivim promenama, a posledice jedne izmene često su se pojavljivale daleko od mesta na kojem je načinjena.
Simula je sa druge strane još šezdesetih godina uvela klase, objekte, nasleđivanje i virtuelne procedure, pružajući programerima nov način da stvarnost prevedu u jezik računara. Procesi, poruke, uređaji i učesnici nekog sistema mogli su dobiti sopstvena svojstva, ponašanje i odnose sa drugim delovima programa. Ta izražajnost donosila je veliku misaonu prednost, ali tadašnje implementacije nisu uvek mogle da ponude brzinu, prenosivost i neposredan pristup sistemskim resursima koji su bili presudni u telekomunikacijama, operativnim sistemima i drugim zahtevnim oblastima. Bjarne Stroustrup prepoznao je prostor između tih svetova i postavio pitanje koje će odrediti njegov životni rad: može li programer dobiti apstrakciju visokog nivoa, a istovremeno sačuvati kontrolu nad stvarnom cenom njenog izvršavanja?
Potrebu za takvim jezikom osetio je tokom istraživanja distribuiranih sistema, u kojima više računara i procesa istovremeno razmenjuje poruke, menja stanje i reaguje na kvarove. Simuline klase pomagale su mu da takve odnose izrazi jasno, dok su ograničenja njenih implementacija otežavala izgradnju dovoljno brzih i pouzdanih programa. Jezici bliži mašini donosili su potrebne performanse, ali su složenu arhitekturu ponovo pretvarali u teško pregledan splet procedura i podataka. Iz tog iskustva nastala je zamisao da se jeziku C dodaju snažnija sredstva za oblikovanje velikih sistema, uz očuvanje njegove prenosivosti, efikasnosti i bliske veze sa hardverom.
Stroustrup je 1979. godine u Bellovim laboratorijama započeo razvoj jezika koji je nazvao „C sa klasama”. C je ostao njegovo čvrsto tlo: model izvršavanja, funkcije, izrazi, pokazivači i mogućnost povezivanja sa već postojećim sistemskim kodom. Klase su donele drugačiji način organizovanja. Podaci koji opisuju jedan pojam i operacije dozvoljene nad njima mogli su da se objedine u smislenu celinu, čija se unutrašnja građa štiti iza pažljivo oblikovanog interfejsa. Program je zahvaljujući tome mogao da bude podeljen na delove sa jasnim odgovornostima, dok je svaki deo čuvao pravila sopstvenog ispravnog ponašanja.
Klasa je u takvom jeziku postala mnogo više od zgodnog omotača oko grupe promenljivih. Konstruktor je određivao kako objekat nastaje u valjanom stanju, destruktor je brinuo o njegovom urednom završetku, a funkcije članice povezivale su ponašanje sa podacima na koje se ono odnosi. Kontrola pristupa omogućavala je da se pojedinosti implementacije sakriju od ostatka programa, dok su nasleđivanje i virtuelne funkcije pružali način da se zajedničke osobine izraze jednom, a zatim prilagode različitim vrstama objekata. Složenost je time dobijala unutrašnji red: umesto da svaki deo sistema poznaje svaki detalj svih ostalih delova, komponente su mogle da razgovaraju kroz jasno definisane granice.
Jedno od trajnih načela jezika postalo je pravilo da programer ne treba da plaća za mogućnost koju ne koristi. Jednostavan objekat mogao je u memoriji ostati jednako kompaktan kao odgovarajuća struktura napisana u jeziku C, dok su se dodatni mehanizmi plaćali onda kada su zaista bili potrebni. Stroustrup je apstrakciju posmatrao kao sredstvo za jasnije mišljenje, ali je zahtevao da njena cena ostane razumljiva i proverljiva. Programer je mogao da oblikuje pojam visokog nivoa, a zatim utvrdi koliko memorije zauzima, kada nastaje, kako se prenosi i kakve operacije procesor izvršava u njegovo ime.
Prva implementacija jezika pokazala je Stroustrupovu izrazitu inženjersku praktičnost. Prevodilac nazvan Cfront pretvarao je „C sa klasama”, a zatim i C++, u izvorni kod jezika C, koji se potom obrađivao postojećim C prevodiocem. Novi jezik je zahvaljujući tome mogao da stigne na brojne računarske platforme bez izgradnje zasebnog generatora mašinskog koda za svaku od njih. Postojeća infrastruktura nije odbačena, već je pretvorena u most kojim je inovacija mogla da uđe u stvarne projekte, sarađuje sa već napisanim bibliotekama i odmah se suoči sa zahtevima svakodnevnog programerskog rada.
Tokom prvih godina jezik je dobijao reference, poboljšanu proveru tipova, preopterećivanje funkcija i operatora, virtuelne funkcije i druga sredstva potrebna za izražavanje sve složenijih struktura. Preopterećivanje je omogućilo da ista operacija dobije značenje prilagođeno različitim tipovima podataka, pa su kompleksni brojevi, matrice, grafički objekti ili drugi pojmovi mogli da se koriste izrazima bliskim jeziku svoje oblasti. Takva sloboda zahtevala je meru i disciplinu: pažljivo izabrane apstrakcije činile su kod razgovetnijim, dok je proizvoljna upotreba istih mogućnosti mogla da zamagli njegov smisao. U toj napetosti već se nazirala priroda C++ — jezik velike izražajne moći čiji kvalitet snažno zavisi od znanja i odgovornosti njegovog korisnika.
Godine 1983. „C sa klasama” dobio je ime C++, na predlog Stroustrupovog saradnika Ricka Mascittija. Oznaka ++ u jeziku C označava uvećavanje vrednosti, pa je ime duhovito i sažeto predstavljalo novi jezik kao razvojni korak koji čuva vezu sa svojim poreklom. Prvo izdanje knjige The C++ Programming Language i prva komercijalna verzija jezika pojavili su se 1985. godine. Knjiga je u vremenu bez međunarodnog standarda imala ulogu zajedničkog uporišta: programerima, nastavnicima i tvorcima prevodilaca objašnjavala je sintaksu, semantiku i projektantske namere jezika, ali i način razmišljanja potreban da bi njegove mogućnosti služile preglednosti umesto gomilanju mehanizama.
C++ se brzo proširio u oblastima u kojima su veliki sistemi morali da spoje složenu unutrašnju arhitekturu sa visokim performansama. Telekomunikaciona infrastruktura, grafički sistemi, baze podataka, prevodioci, razvojni alati, finansijske platforme, simulacije i operativna okruženja zahtevali su softver koji koristi hardver veoma efikasno, a ipak ostaje dovoljno organizovan za rad velikih timova. C++ je programerima omogućio da naprave tipove prilagođene sopstvenoj oblasti i da ih zatim koriste gotovo kao ugrađene delove jezika. Greške su se u mnogim slučajevima mogle otkriti već tokom prevođenja, dok su jasno razdvojeni interfejsi i implementacije olakšavali promenu jednog dela sistema bez narušavanja čitave građevine.
Iz povezivanja životnog veka objekta sa resursima razvio se obrazac poznat kao RAII, odnosno pribavljanje resursa tokom inicijalizacije. Memorija, datoteka, mrežna veza, zaključavanje ili drugi ograničeni resurs poverava se objektu koji ga preuzima pri nastanku i oslobađa pri uništenju. Kada program napusti određeni opseg, destruktor se poziva automatski, uključujući situacije u kojima je izvršavanje prekinuto izuzetkom. Odgovornost za oslobađanje resursa tako se ugrađuje u samu strukturu programa, umesto da zavisi od toga hoće li se programer setiti svake moguće putanje izlaska. Ovaj princip ostao je jedan od najvažnijih doprinosa C++ razvoju pouzdanog sistemskog softvera.
Dalji razvoj pokazao je da C++ neće ostati ograničen na objektno orijentisano programiranje. Šabloni su otvorili prostor generičkom programiranju, u kojem se algoritam oblikuje prema sposobnostima koje očekuje od podataka, umesto prema jednom unapred određenom tipu. Funkcija za sortiranje, kontejner ili matematička operacija mogli su da rade sa čitavim porodicama tipova, uz specijalizaciju i proveru tokom prevođenja. Programeri su dobili mogućnost da opšte ideje izraze jednom i ponovo ih koriste bez obavezne cene dinamičkog izvršavanja, čime je jezik povezao matematičku opštost sa zahtevima veoma brzog koda.
Snagu tog pristupa naročito je pokazala Standardna biblioteka šablona, razvijena prvenstveno radom Aleksandra Stepanova i Meng Li. STL je razdvojio kontejnere, algoritme i iteratore tako da se mogu slobodno kombinovati. Algoritam više nije morao da poznaje unutrašnju građu svakog kontejnera, niti je svaki kontejner morao da sadrži sopstvenu verziju svih potrebnih postupaka. Stroustrupova podrška njenom uključivanju u standard pokazala je da je jezik prerastao delo jednog autora. Njegove najvažnije mogućnosti dalje su otkrivali i oblikovali istraživači, inženjeri, tvorci biblioteka i korisnici koji su u zajedničkim mehanizmima pronalazili nove načine za izražavanje problema.
Rast popularnosti istovremeno je donosio opasnost od rasparčavanja. Proizvođači prevodilaca uvodili su sopstvena proširenja i pojedina pravila tumačili na različite načine, zbog čega program napisan za jedan sistem nije uvek mogao jednostavno da se prenese na drugi. Međunarodni proces standardizacije okupio je proizvođače alata, kompanije, istraživače, korisnike i predstavnike nacionalnih tela za standardizaciju. Prvi međunarodni standard objavljen je 1998. godine, objedinjujući jezik i njegovu standardnu biblioteku. C++ je tako postao zajedničko tehničko dobro održavano kroz javne predloge, stručne rasprave, implementaciona iskustva i međunarodno usaglašavanje.
Njegov uticaj posebno je vidljiv u softveru koji mora da koristi hardver blizu njegovih granica. Jezgra internet pregledača, grafički pogoni, baze podataka, prevodioci, telekomunikacione mreže, sistemi u vozilima, robotske platforme, alati za obradu slike i zvuka, naučni instrumenti i finansijske aplikacije oslanjali su se na sposobnost C++ da poveže apstrakciju sa preciznim upravljanjem memorijom i vremenom izvršavanja. U industriji video-igara omogućio je izgradnju pogona koji istovremeno upravljaju grafikom, fizikom, zvukom, mrežnom komunikacijom i ponašanjem virtuelnog sveta, često pod neumoljivim ograničenjem da svaki kadar mora biti obrađen za svega nekoliko milisekundi.
Dugovečnost jezika donela je i veliku slojevitost. Očuvanje kompatibilnosti sa jezikom C i starijim C++ programima omogućilo je kompanijama da postepeno usvajaju novije tehnike, zaštite decenije ulaganja i nastave da razvijaju sisteme čiji se radni vek meri desetinama godina. Ista odluka otežala je uklanjanje zastarelih, opasnih ili nedoslednih osobina. Savremeni obrasci dele prostor sa tehnikama nastalim u drugačijem hardverskom i programerskom dobu, pa C++ od korisnika zahteva sposobnost da razlikuje mogućnost koju jezik dopušta od rešenja koje je u datom programu mudro primeniti.
Najozbiljnije kritike usmerene su na složenost jezika i bezbednost memorije. Neposredan rad sa adresama i pokazivačima pruža kontrolu potrebnu pojedinim vrstama sistemskog programiranja, ali greške mogu izazvati prekoračenje granica bafera, pristup već oslobođenoj memoriji, rušenje programa i ozbiljne bezbednosne ranjivosti. Savremeni C++ zato podstiče korišćenje standardnih kontejnera, pametnih pokazivača, algoritama, opsega, jasnog vlasništva nad resursima i alata za statičku i dinamičku analizu. Jezik pruža sve snažnije mogućnosti za bezbedan stil, dok njegovo istorijsko nasleđe i dalje ostavlja otvorena vrata rizičnim postupcima, naročito u starom kodu.
Velika obnova započeta standardom C++11 pokazala je sposobnost jezika da se temeljno menja uz očuvanje veze sa svojim poreklom. Lambda izrazi, automatsko zaključivanje tipova, semantika premeštanja, pametni pokazivači, podrška za niti i brojna proširenja standardne biblioteke omogućili su izražajniji i pouzdaniji način rada. Kasnija izdanja donela su koncepte, opsege, korutine, module i nova sredstva za programiranje tokom prevođenja. C++ je time dobio redovan razvojni ritam u kojem iskustva iz industrije, istraživanja i implementacija postepeno ulaze u međunarodni standard.
Inženjerska elegancija C++ počiva na smeloj nameri da se složenost velikih sistema ukroti kroz tipove, objekte, generičke algoritme, biblioteke i jasno upravljanje životnim vekom resursa, uz očuvanje odgovornosti za ono što računar zaista izvršava. Stroustrup je pokazao da apstraktno mišljenje i razumevanje mašine mogu pripadati istom programerskom obrazovanju. Programer dobija slobodu da gradi sopstveni jezik pojmova, ali zajedno sa njom prihvata obavezu da razume cenu, granice i posledice svojih odluka.
Bez Stroustrupove realizacije razvoj softvera mnogo bi duže ostao podeljen između sistemskih jezika koji nude kontrolu i jezika višeg nivoa koji olakšavaju organizovanje složenih programa. C++ je pružio jedan od prvih velikih industrijskih dokaza da klase, generički algoritmi, stroža provera tipova i automatsko upravljanje životnim vekom resursa mogu služiti softveru koji radi pod najzahtevnijim vremenskim i memorijskim ograničenjima. Njegovo nasleđe živi i u jezicima koji ga nastavljaju i u onima koji pokušavaju da prevaziđu njegove slabosti, jer svi iznova odgovaraju na pitanje koje je Stroustrup postavio: koliko visoko može da se uzdigne ljudska misao, a da ne izgubi odgovornost za mašinu koja će tu misao pretvoriti u delo?