Co robi C ++ lepiej niż D?


135

Niedawno uczyłem się D i zaczynam się trochę zaznajomić z językiem. Wiem, co oferuje, nie wiem jeszcze, jak korzystać ze wszystkiego, i niewiele wiem o idiomach D i tak dalej, ale uczę się.

Lubię D. To fajny język, będący w pewnym sensie ogromną aktualizacją do C i ładnie wykonany. Żadna z funkcji nie wydaje się być „przykręcona”, ale w rzeczywistości całkiem przemyślana i dobrze zaprojektowana.

Często słyszysz, że D był tym, czym powinien być C ++ (pozostawiam pytanie, czy jest to prawdą dla każdego i dla wszystkich, aby sami decydowali, aby uniknąć niepotrzebnych wojen o płomienie). Słyszałem też od kilku programistów C ++, że podoba im się D znacznie bardziej niż C ++.

Ja, choć znam C, nie mogę powiedzieć, że znam C ++. Chciałbym usłyszeć od kogoś znającego zarówno C ++, jak i D, jeśli uważają, że jest coś, co C ++ robi lepiej niż D jako język (co oznacza, że ​​nie jest to zwykłe „ma więcej bibliotek stron trzecich” lub „jest więcej zasobów” lub „ istnieje więcej zadań wymagających C ++ niż D ”).

D został zaprojektowany przez niektórych bardzo wykwalifikowanych programistów C ++ ( Walter Bright i Andrei Alexandrescu , z pomocą społeczności D), aby naprawić wiele problemów, które miał C ++, ale czy było coś, co tak naprawdę nie poprawiło się? Coś, za czym tęsknił? Coś, co Twoim zdaniem nie było lepszym rozwiązaniem?

Zauważ też, że mówię o D 2.0 , a nie D 1.0 .


15
Upewniłem się, że społeczność D to widzi, ponieważ jestem pewien, że jest tutaj o wiele więcej programistów C ++ niż D deweloperów. W ten sposób uzyskasz ciekawsze lub przynajmniej zróżnicowane odpowiedzi.
Klaim

7
Ponadto D2 został zaprojektowany przez Waltera Brighta, ale także z Alexandrescu. Możesz to naprawić w swoim pytaniu.
Klaim

2
@Klaim: było (i nadal jest) duże zaangażowanie społeczności w D i bibliotekę standardową.
Michał Minich

28
@Anto Jako język C ++ jest o wiele lepszy niż D w sprawianiu, że programista nienawidzi swojego życia.
Arlen

6
@jokoon: Właściwie tak, przy bardzo małej pracy: digitalmars.com/d/2.0/interfaceToC.html
Anto

Odpowiedzi:


124

Większość rzeczy, które C ++ „robi” lepiej niż D, to meta rzeczy: C ++ ma lepsze kompilatory, lepsze narzędzia, bardziej dojrzałe biblioteki, więcej powiązań, więcej ekspertów, więcej samouczków itp. Zasadniczo ma coraz więcej wszystkich rzeczy zewnętrznych, które możesz oczekiwałbym od bardziej dojrzałego języka. To jest bezdyskusyjne.

Jeśli chodzi o sam język, moim zdaniem C ++ radzi sobie lepiej niż D. Prawdopodobnie jest ich więcej, ale oto kilka, które mogę wymienić na czubku głowy:

C ++ ma lepiej przemyślany system typów
W tej chwili istnieje sporo problemów z systemem typów w D, które wydają się być niedopatrzeniem w projekcie. Na przykład obecnie niemożliwe jest skopiowanie struktury const do struktury non-const, jeśli struktura zawiera odwołania do obiektów klasy lub wskaźniki ze względu na przechodniość const i sposób działania konstruktorów postblit na typach wartości. Andrei mówi, że wie, jak to rozwiązać, ale nie podał żadnych szczegółów. Problem można z pewnością naprawić (wprowadzenie konstruktorów kopiujących w stylu C ++ byłoby jedną naprawą), ale obecnie jest to poważny problem w języku.

Innym problemem, który mnie zepsuł, jest brak logicznej stałej (tj. Nie mutablejak w C ++). Jest to świetne do pisania kodu zabezpieczającego wątki, ale utrudnia (niemożliwe?) Robienie leniwej intralizacji w obiektach const (pomyśl o funkcji const „get”, która konstruuje i buforuje zwracaną wartość przy pierwszym wywołaniu).

Wreszcie, biorąc pod uwagę te istniejące problemy, martwię się o tym, jak reszta systemu typu ( pure, sharedetc.) będą wchodzić w interakcje ze wszystkim w języku, gdy zostaną oddane do użytku. Standardowa biblioteka (Phobos) obecnie w bardzo niewielkim stopniu korzysta z zaawansowanego systemu typu D, więc myślę, że uzasadnione jest pytanie, czy wytrzyma stres. Jestem sceptyczny, ale optymistyczny.

Zauważ, że C ++ ma brodawki w systemie typów (np. Stała nieprzechodnia, wymagająca iteratori const_iterator), które sprawiają, że jest dość brzydka, ale chociaż system typów w C ++ jest trochę niewłaściwy w części, nie powstrzymuje cię przed wykonaniem pracy jak D czasami robi.

Edycja: Aby wyjaśnić, uważam, że C ++ ma lepiej przemyślany system typów - niekoniecznie lepszy - jeśli ma to sens. Zasadniczo w DI uważam, że istnieje ryzyko związane ze stosowaniem wszystkich aspektów jego systemu typów, które nie są obecne w C ++.

D jest czasem trochę zbyt wygodne
Jedną z krytycznych uwag, które często słyszysz o C ++, jest to, że ukrywa przed Tobą pewne problemy niskiego poziomu, np. Proste zadania, takie jak a = b;wykonywanie wielu operacji, takich jak wywoływanie operatorów konwersji, wywoływanie operatorów przypisania przeciążenia itp., Które mogą być trudno zobaczyć z kodu. Niektórzy to lubią, inni nie. Tak czy inaczej, w D jest gorzej (lepsza?) Ze względu na takie rzeczy jak opDispatch, @property, opApply, lazyktóre mają potencjał, aby zmienić kod niewinnie patrząc na rzeczy, że nie należy się spodziewać.

Nie sądzę, aby był to duży problem osobiście, ale niektórzy mogą uznać to za odrażające.

D wymaga odśmiecania.
Może to być postrzegane jako kontrowersyjne, ponieważ możliwe jest uruchomienie D bez GC. Jednak tylko dlatego, że jest to możliwe, nie oznacza, że ​​jest to praktyczne. Bez GC tracisz wiele funkcji D, a korzystanie ze standardowej biblioteki byłoby jak chodzenie po polu minowym (kto wie, które funkcje przydzielają pamięć?). Osobiście uważam, że używanie D bez GC jest całkowicie niepraktyczne, a jeśli nie jesteś fanem GC (tak jak ja), może to być dość odrażające.

Naiwne definicje tablic w D alokują pamięć
To jest mój wkurzający zwierzak:

int[3] a = [1, 2, 3]; // in D, this allocates then copies
int a[3] = {1, 2, 3}; // in C++, this doesn't allocate

Najwyraźniej, aby uniknąć przydziału w D, musisz zrobić:

static const int[3] staticA = [1, 2, 3]; // in data segment
int[3] a = staticA; // non-allocating copy

Te małe przydziały „za twoimi plecami” są dobrym przykładem moich dwóch poprzednich punktów.

Edycja: Zauważ, że jest to znany problem, nad którym pracujemy.
Edycja: Zostało to naprawione. Nie następuje przydział.

Wniosek
Skoncentrowałem się na negatywach D w porównaniu do C ++, ponieważ o to właśnie zadałem pytanie, ale proszę nie postrzegać tego postu jako stwierdzenia, że ​​C ++ jest lepszy niż D. Mogłabym z łatwością zrobić większy post z miejsc, w których D jest lepszy niż C ++. Od Ciebie zależy, który z nich wybrać.


Patrzyłem na D kilka lat temu (przed 2.0). Odśmiecanie nie było wtedy tak naprawdę wymagane - było tam domyślnie, ale można zrezygnować z kodu niskiego poziomu. Pomyślałem, że nie mam racji w tym, że nie mogłem znaleźć sposobu, aby włączyć się ponownie. Na przykład w kontenerze opartym na drzewie kod biblioteki może zarządzać pamięcią dla samych węzłów drzewa. Drzewo jako całość wciąż może być kolekcjonowane, a IIRC jest niszczycielem, który zbiera wszystkie te węzły. Ale obiekty, do których odwołują się dane w tym kontenerze, również powinny być kolekcjonowalne - powinien istnieć hak do oznaczania wszystkich elementów danych w drzewie dla GC.
Steve314,

3
Nadal możesz wyłączyć GC dla kodu niskiego poziomu - Peter mówi, że język zależy obecnie od niego. Możesz także powiedzieć GC, aby skanował zakresy poza zarządzaną stertą za pomocą API: GC.addRange z core.memory .
Vladimir Panteleev

+1 za wskazanie, że biblioteka standardowa D jest odśmiecana i że kod GC-off nie jest płynną interakcją. To nie jest coś, o czym myślałem, ale wydaje się, że to poważna przeszkoda do pokonania.
masonk

132

Kiedy dołączyłem do rozwoju D, byłem w szczególnej sytuacji, ponieważ byłem jedną z osób, które wiedzą najwięcej o C ++. Teraz jestem w jeszcze bardziej szczególnej sytuacji, aby być także jedną z osób, które wiedzą najwięcej na temat D. Nie mówię tego o odpowiednich prawach do przechwalania się i chwaleniu, a jedynie o tym, że jestem ciekawy korzystna pozycja do udzielenia odpowiedzi na to pytanie. To samo dotyczy Waltera.

Ogólnie rzecz biorąc, pytanie, co C ++ (a przez to mam na myśli C ++ 2011) lepiej niż D, jest tak samo wewnętrznie sprzeczne jak pytanie: „Jeśli zapłacisz profesjonaliście za posprzątanie domu, w jakich miejscach on opuści brudniejszy niż wcześniej? ” Niezależnie od tego, jaką wartością było to, że C ++ mogło to zrobić, czego D nie potrafił, zawsze było dla mnie i Waltera jak obolały kciuk, więc prawie z definicji C ++ nigdy nie może zrobić niczego, co nie jest w zasięgu D.

Jedną rzeczą, która rzadko jest rozumiana w projektowaniu języka (ponieważ niewiele osób ma szczęście, aby to zrobić) jest to, że jest o wiele mniej niewymuszonych błędów, niż może się wydawać. Wielu z nas użytkowników języka patrzy na jakąś konstrukcję lub inną i mówi: „Ew! To takie złe! Co oni sobie myśleli?” Faktem jest, że najbardziej niezręczne przypadki w języku są następstwem kilku fundamentalnych decyzji, które wszystkie są rozsądne i pożądane, ale zasadniczo konkurują ze sobą lub są ze sobą sprzeczne (np. Modułowość i wydajność, zwięzłość i kontrola itp.).

Mając to na uwadze, wymienię kilka rzeczy, o których mogę pomyśleć, i dla każdego wyjaśnię, w jaki sposób wybór D wynika z chęci spełnienia innej, wyższej karty, czarteru.

  1. D zakłada, że ​​wszystkie obiekty są ruchome przez kopiowanie bitowe. Pozostawia to mniejszość projektów w C ++, szczególnie tych, które wykorzystują wewnętrzne wskaźniki, tj. Klasę zawierającą wskaźniki wewnątrz siebie. (Każdy taki projekt można przetłumaczyć na D bez żadnych lub nieznacznych kosztów wydajności, ale wiąże się to z koniecznością tłumaczenia). Podjęliśmy decyzję, aby znacznie uprościć język, zwiększyć efektywność kopiowania obiektów bez interwencji użytkownika lub przy minimalnej interwencji użytkownika i uniknąć cały tekst budowy kopii i odniesienia do wartości są w całości przedstawione.

  2. D nie zezwala na typy o niejednoznacznej płci (które nie mogą zdecydować, czy są to typy wartościowe czy referencyjne). Takie projekty są jednogłośnie odrzucane w C ++ i prawie zawsze są błędne, ale niektóre z nich są technicznie poprawne. Dokonaliśmy tego wyboru, ponieważ uniemożliwia to w większości niepoprawny kod i tylko niewielki ułamek poprawnego kodu, który można przeprojektować. Uważamy, że to dobry kompromis.

  3. D nie zezwala na hierarchie wielu korzeni. Poprzedni plakat był bardzo podekscytowany tym konkretnym tematem, ale jest to dobrze zdeptany grunt i nie ma wyraźnej przewagi hierarchicznych hierarchii nad hierarchiami, które mają wspólny katalog główny.

  4. W D nie możesz rzucić np. Int. Musisz rzucić obiekt dziedziczący Throwable. Żaden spór nie ma lepszego stanu rzeczy w D, ale cóż, C ++ może to zrobić, czego D nie potrafi.

  5. W C ++ jednostką enkapsulacji jest klasa. W D jest to moduł (tzn. Plik). Walter podjął tę decyzję z dwóch powodów: w naturalny sposób odwzorować enkapsulację na semantykę ochrony systemu plików i uniknąć potrzeby posiadania „przyjaciela”. Ten wybór bardzo dobrze integruje się z ogólną konstrukcją modułową D. Można by zmienić rzeczy tak, by były bardziej podobne do C ++, ale to by wymusiło; Wybrane zakresy enkapsulacji C ++ są dobre tylko dla fizycznego projektu C ++.

Może być jedna lub dwie mniejsze rzeczy, ale ogólnie to powinno być to.


6
@DeadMG: Aby to działało w C ++, przenoszony obiekt wymagałby wskaźnika wstecz do obiektu wskazującego na niego (aby mógł aktualizować się podczas tworzenia kopii). W takim przypadku w D można mimo wszystko użyć konstruktora postblit, aby zaktualizować wskaźnik. Proszę się nie kłócić przeciwko D, jeśli tylko masz na ten temat wiedzę.
Peter Alexander

13
@Peter: To powinno być odniesieniem, nawet jeśli jego żywotność jest ściśle oparta na zakresie? Powinienem marnować koszty związane z dynamicznym przydzielaniem go oraz koszty pośrednie, pamięci podręcznej i kolekcji, ponieważ chcę to alias? Mam również nadzieję, że kolektor zbierze go deterministycznie, dla równoważnej semantyki. Wyraźnie nie ma nad tym kontroli.
DeadMG

3
@sbi: Istnienie najwyższej klasy w ogóle nie wpływa na twoje wybory. W kratce typu klasy zawsze jest góra i dół. Dno jest wyraźne tylko w kilku językach . Góra (tj. Obiekt itp.) Jest wyraźna w większej liczbie języków. Te typy zawsze istnieją w koncepcji; gdy są również dostępne, oferują po prostu kilka dodatkowych udogodnień dla użytkownika języka bez żadnych problemów.
Andrei Alexandrescu,

6
@quant_dev: z przyjemnością usłyszysz, że projekt GSoC jest już w dobrej formie i koncentruje się na wysokowydajnej algebrze liniowej przy użyciu BLAS. Zapewnia także „naiwne” implementacje odpowiednich prymitywów do celów testowania i testów porównawczych. Aby odpowiedzieć na drugie pytanie, Java ustawia pasek dość nisko przy porównywaniu bibliotek numerycznych. Zawsze będzie miał problem z przekroczeniem bariery JNI w celu uzyskania dostępu do wysokowydajnych bibliotek algebry, a składnia będzie zła, ponieważ Java nie ma przeciążenia operatora.
Andrei Alexandrescu,

4
@PeterAlexander: DeadMG ma rację. „Nie powinieneś używać wskaźników do typów wartości” jest wyraźnie nieświadomy faktu, że wskaźniki w dowolnym języku są zwykle używane z typami wartości (czy naprawdę spodziewasz się, że zobaczysz Object*tak powszechnie używane jako int*?), A D wydaje się całkowicie ignorować kara za wydajność lub twierdzenie, że nie istnieje. To oczywiście nieprawda - w wielu przypadkach brak pamięci podręcznej jest dość zauważalny, więc C ++ zawsze będzie miał tę przewagę elastyczności nad D.
Mehrdad

65

Myślę, że będzie ci bardzo trudno znaleźć wiele w D, co jest obiektywniegorzej niż C ++. Większość problemów z D, w których można obiektywnie powiedzieć, że jest gorzej, to albo problemy z jakością implementacji (które są na ogół spowodowane młodym językiem i implementacją i zostały naprawione w zawrotnym tempie), albo są to problemy z brakiem bibliotek stron trzecich (które przyjdą z czasem). Sam język jest na ogół lepszy niż C ++, a przypadki, w których C ++, jako język, jest lepszy, zwykle albo będą tam, gdzie jest kompromis, w którym C ++ poszedł w jedną stronę, a D poszedł w inną, lub gdzie ktoś ma subiektywne powody, dla których myślę, że jedno jest lepsze od drugiego. Ale liczba obiektywnych powodów, dla których C ++, jako język, jest lepszy, prawdopodobnie będzie niewielka.

W rzeczywistości muszę naprawdę rozwalić mózg, aby wymyślić powody, dla których C ++, jako język, jest lepszy od D. To, co ogólnie przychodzi na myśl, to kwestia kompromisów.

  1. Ponieważ D's const jest przechodni, a ponieważ język jest niezmienny , to ma o wiele silniejsze niż C ++ gwarancje 's const, co oznacza, że D nie ma i nie może mieć mutable. Nie może mieć logicznej stałej . Tak więc zyskujesz ogromną przewagę dzięki systemowi const D, ale w niektórych sytuacjach po prostu nie możesz używać consttak jak w C ++.

  2. D ma tylko jeden operator rzutowania, podczas gdy C ++ ma 4 (5, jeśli policzysz operator rzutowania C). To sprawia, że ​​radzenie sobie z rzutami w D jest łatwiejsze w ogólnym przypadku, ale jest problematyczne, gdy naprawdę chcesz dodatkowych komplikacji / korzyści, które zapewniają const_casti jego bracia. Ale D jest w rzeczywistości na tyle potężny, że można użyć szablonów do implementacji rzutowań C ++, więc jeśli naprawdę ich potrzebujesz, możesz je mieć (a nawet mogą kiedyś znaleźć się w standardowej bibliotece D).

  3. D ma znacznie mniej niejawnych rzutowań niż C ++ i jest o wiele bardziej prawdopodobne, że deklarują, że dwie funkcje są ze sobą w konflikcie (zmuszając cię do bardziej szczegółowego określenia, które funkcje masz na myśli - albo z rzutowaniami, albo podając pełną ścieżkę modułu ). Czasami może to być denerwujące, ale zapobiega wszelkim problemom z przejmowaniem funkcji . Wiesz, że naprawdę wywołujesz funkcję, którą masz na myśli.

  4. System modułów D jest znacznie czystszy niż #include C ++ (nie wspominając, znacznie szybszy w kompilacji), ale brakuje mu jakiejkolwiek przestrzeni nazw poza samymi modułami. Tak więc, jeśli chcesz mieć przestrzeń nazw w module, musisz przejść trasę Java i użyć funkcji statycznych dla klasy lub struktury. Działa, ale jeśli naprawdę chcesz przestrzeni nazw, to oczywiście nie jest tak czyste jak prawdziwa przestrzeń nazw. Jednak w większości sytuacji przestrzeń nazw, którą zapewniają same moduły, jest duża (i dość wyrafinowana, jeśli chodzi o rzeczy takie jak konflikty).

  5. Podobnie jak Java i C #, D ma pojedyncze dziedziczenie zamiast wielokrotnego dziedziczenia, ale w przeciwieństwie do Java i C #, daje to fantastyczne sposoby uzyskania tego samego efektu bez wszystkich problemów, jakie ma wielokrotne dziedziczenie C ++ (a wielokrotne dziedziczenie C ++ może być bardzo nieuporządkowane czasami). D ma nie tylko interfejsy , ale ma także mieszanki łańcuchów , szablony i alias tego . Tak więc ostateczny wynik jest prawdopodobnie silniejszy i nie ma wszystkich problemów, które powoduje wielokrotne dziedziczenie C ++.

  6. Podobnie jak w C #, D oddziela struktury i klasy . Klasy są typami referencyjnymi, które mają dziedziczenie i pochodzą od nich Object, podczas gdy struktury są typami wartości bez dziedziczenia. Ten rozdział może być zarówno dobry, jak i zły. Pozbywa się klasycznego problemu krojenia w C ++ i pomaga oddzielić typy, które są tak naprawdę typami wartości, od tych, które powinny być polimorficzne, ale na początku przynajmniej rozróżnienie może być denerwujące dla programisty C ++. Ostatecznie ma to wiele zalet, ale zmusza cię do nieco odmiennego traktowania swoich typów.

  7. Użytkownika funkcje z klas są polimorficzne domyślnie. Nie można zadeklarować, że nie są wirtualne . Kompilator decyduje, czy mogą być (co tak naprawdę ma miejsce tylko wtedy, gdy są ostateczne i nie zastępują funkcji z klasy podstawowej). W niektórych przypadkach może to stanowić problem z wydajnością. Jeśli jednak naprawdę nie potrzebujesz polimorfizmu, wystarczy użyć struktur i nie stanowi to problemu.

  8. D ma wbudowany pojemnik na śmieci . Wielu z C ++ uznałoby to za poważną wadę i prawdę mówiąc, w chwili obecnej jego wdrożenie może wymagać poważnej pracy. Poprawia się, ale zdecydowanie nie jest jeszcze na równi z urządzeniem do usuwania śmieci Java. Łagodzi to jednak dwa czynniki. Po pierwsze, jeśli używasz struktur i innych typów danych na stosie, nie jest to duży problem. Jeśli twój program nie stale przydziela i zwalnia rzeczy na stosie, wszystko będzie dobrze. Po drugie, możesz pominąć śmietnik, jeśli chcesz i po prostu użyć C malloci free. Istnieje kilka funkcji językowych (takich jak dzielenie tablic), których należy unikać lub zachować ostrożność, a niektóre ze standardowych bibliotek nie są tak naprawdę przydatne bez przynajmniej użycia GC (szczególnie przetwarzania ciągów), ale można pisać w D bez użycia modułu wyrzucania elementów bezużytecznych, jeśli naprawdę chcesz. Rozsądną rzeczą jest prawdopodobnie ogólne użycie go, a następnie unikanie go tam, gdzie profilowanie pokazuje, że powoduje problemy z kodem krytycznym dla wydajności, ale można tego całkowicie uniknąć, jeśli chcesz. A jakość wdrożenia GC poprawi się z czasem, eliminując wiele obaw, które może powodować używanie GC . Ostatecznie GC nie będzie tak dużym problemem, a w przeciwieństwie do Javy możesz tego uniknąć, jeśli chcesz.

Prawdopodobnie są też inni, ale w tej chwili mogę to wymyślić. A jeśli zauważysz, wszystkie są kompromisami. D zdecydował się robić pewne rzeczy inaczej niż C ++, które mają wyraźną przewagę nad tym, jak robi to C ++, ale mają też pewne wady. To, co jest lepsze, zależy od tego, co robisz, aw wielu przypadkach prawdopodobnie na początku będzie się wydawało gorsze, a potem nie będziesz mieć z tym problemu, kiedy się przyzwyczaisz. Jeśli cokolwiek, problemy w D będą na ogół nowe spowodowane przez nowe rzeczy, których inne języki nie zrobiły wcześniej lub nie zrobiły w sposób podobny do D. Ogólnie rzecz biorąc, D bardzo dobrze nauczył się na błędach C ++.

A D, jako język, poprawia się w stosunku do C ++ na tyle sposobów, że uważam, że ogólnie rzecz biorąc, D jest obiektywnie lepszy.

  1. D ma kompilację warunkową . Jest to jedna z funkcji, których często brakuje mi podczas programowania w C ++. Jeśli C ++ to doda, to C ++ poprawi się skokowo, jeśli chodzi o rzeczy takie jak szablony.

  2. D ma odbicie w czasie kompilacji .

  3. Zmienne są domyślnie lokalne dla wątków, ale mogą być, sharedjeśli chcesz, aby były. To sprawia, że ​​radzenie sobie z wątkami jest znacznie czystsze niż w C ++. Masz pełną kontrolę. Możesz używać immutablei przekazywać wiadomości do komunikacji między wątkami, lub możesz tworzyć zmienne sharedi robić to w sposób C ++ z muteksami i zmiennymi warunkowymi. Nawet to zostało ulepszone w stosunku do C ++ dzięki wprowadzeniu synchronizacji (podobnej do C # i Java). Tak więc sytuacja wątków w D jest znacznie lepsza niż w C ++.

  4. Szablony D są znacznie potężniejsze niż szablony C ++, co pozwala robić znacznie więcej, znacznie łatwiej. Dzięki dodaniu ograniczeń szablonów komunikaty o błędach są znacznie lepsze niż w C ++. D sprawia, że ​​szablony są bardzo wydajne i użyteczne. To nie przypadek, że autor Modern C ++ Design jest jednym z głównych współpracowników D. Uważam, że szablonów C ++ poważnie brakuje w porównaniu do szablonów D i może to być bardzo frustrujące w momentach programowania w C ++.

  5. D ma wbudowane programowanie kontraktów .

  6. D ma wbudowaną platformę testów jednostkowych .

  7. D ma wbudowaną obsługę Unicode z string(UTF-8), wstring(UTF-16) i dstring(UTF-32). Ułatwia radzenie sobie z Unicode. A jeśli chcesz po prostu używać stringi ogólnie nie martwisz się o Unicode, możesz - chociaż pewne zrozumienie podstaw Unicode pomaga w niektórych standardowych funkcjach biblioteki.

  8. Przeciążenie operatora D jest znacznie ładniejsze niż w C ++, pozwalając na użycie jednej funkcji do przeciążenia wielu operatorów jednocześnie. Najlepszym tego przykładem jest przeciążenie podstawowych operatorów arytmetycznych, a ich implementacje są identyczne, z wyjątkiem operatora. Mixiny łańcuchowe sprawiają, że jest to bardzo proste, dzięki czemu możesz mieć dla nich jedną prostą definicję funkcji.

  9. Tablice D są znacznie lepsze niż tablice C ++. Są nie tylko odpowiednim typem o długości, ale można je dołączać i zmieniać ich rozmiar. Łączenie ich jest łatwe. A co najważniejsze, mają krojenie . To ogromny dar dla wydajnego przetwarzania macierzy. Łańcuchy to tablice znaków w D i nie stanowi to problemu (w rzeczywistości jest świetny!), Ponieważ tablice D są tak potężne.

Mógłbym kontynuować. Wiele ulepszeń, które zapewnia D, to małe rzeczy (np. Używanie thisnazw konstruktorów lub niedozwolone, jeśli instrukcje lub ciała pętli, w których średnikiem jest całe ich ciało), ale niektóre z nich są dość duże, a po dodaniu wszystkiego razem zapewnia znacznie lepsze wrażenia z programowania. C ++ 0x dodaje niektóre funkcje D, których brakowało w C ++ (np. autoI lambdas), ale nawet pomimo wszystkich jego ulepszeń, nadal nie będzie wiele, co byłoby obiektywnie lepsze w C ++ jako języku niż D.

Nie ma wątpliwości, że istnieje wiele subiektywnych powodów, aby lubić się jeden na drugim, a względna niedojrzałość implementacji D może czasami stanowić problem (chociaż ostatnio bardzo szybko się poprawia - zwłaszcza, że ​​repozytoria zostały przeniesione do github ) , a brak bibliotek stron trzecich może zdecydowanie stanowić problem (chociaż fakt, że D może łatwo wywoływać funkcje C - i, w mniejszym stopniu, funkcje C ++ - zdecydowanie łagodzi problem). Ale są to raczej problemy z jakością implementacji niż problemy z samym językiem. A gdy problemy z jakością wykonania zostaną naprawione, korzystanie z D. stanie się o wiele przyjemniejsze

Tak więc przypuszczam, że krótka odpowiedź na to pytanie jest „bardzo mała”. D, jako język, jest ogólnie lepszy od C ++.


2
Języki odśmiecania pamięci używają 2-5 razy więcej pamięci niż języki inne niż GC (zgodnie z wykładem Alexandrescu na YT), więc jest to zdecydowanie problem, jeśli to (użycie pamięci) jest wąskim gardłem.
NoSenseEtAl

9

Wykorzystanie pamięci RAII i stosu

D 2.0 nie pozwala scopena wystąpienie RAII na stosie, ponieważ usunął wartość słowa kluczowego przy przydzielaniu instancji klas na stosie.

Nie można wykonywać dziedziczenia typu wartości w D, tak skutecznie, że zmusza do dokonania alokacji sterty dla dowolnej formy RAII.
To znaczy, chyba że używasz emplace, ale jest to bardzo bolesne w użyciu, ponieważ musisz ręcznie przydzielić pamięć. (Nie znalazłem jeszcze praktycznego zastosowania emplacew D.)


6

C ++ jest znacznie lepszy w zmuszaniu cię do gadatliwości. Może to być lepsze lub gorsze w twoich oczach, w zależności od tego, czy lubisz wnioskowanie, czy gadatliwość.

Porównaj zapamiętywanie w czasie wykonywania w C ++ :

template <typename ReturnType, typename... Args>
function<ReturnType (Args...)> memoize(function<ReturnType (Args...)> func)
{
    map<tuple<Args...>, ReturnType> cache;
    return ([=](Args... args) mutable {
            tuple<Args...> t(args...);
            return cache.find(t) == cache.end()
                ? cache[t] : cache[t] = func(args...);
    });
}

z tą samą rzeczą w D:

auto memoize(F)(F func)
{
    alias ParameterTypeTuple!F Args;
    ReturnType!F[Tuple!Args] cache;
    return (Args args)
    {
        auto key = tuple(args);
        return key in cache ? cache[key] : (cache[key] = func(args));
    };
}

Zauważ, na przykład, dodatkową gadatliwość template <typename ReturnType, typename... Args>względem versus (F), Args...versus Args, args...versus argsitd.
Dla lepszego lub gorszego C ++ jest bardziej gadatliwy.

Oczywiście możesz to zrobić również w D:

template memoize(Return, Args...)
{
    Return delegate(Args) memoize(Return delegate(Args) func)
    {
        Return[Tuple!Args] cache;
        return delegate(Args args)
        {
            auto key = tuple(args);
            return key in cache ? cache[key] : (cache[key] = func(args));
        };
    }
}

i wyglądałyby prawie identycznie, ale wtedy wymagałoby to delegate, podczas gdy oryginał zaakceptował dowolny obiekt możliwy do wywołania. (Wersja C ++ 0x wymagastd::function obiektu, więc w obu przypadkach jest bardziej gadatliwy i restrykcyjny w wejściach ... co może być dobre, jeśli lubisz gadatliwość, a złe, jeśli nie.)


2

Nie wiem dużo o D, ale wielu, wielu programistów C ++ bardzo go nie lubię i osobiście muszę się zgodzić - nie podoba mi się wygląd D i nie będę się zbliżał.

Aby zrozumieć, dlaczego D nie zyskuje większej przyczepności, musisz zacząć od zrozumienia, co przyciąga ludzi do C ++. Jednym słowem powodem numer jeden jest kontrola. Kiedy programujesz w C ++, masz pełną kontrolę nad swoim programem. Chcesz zastąpić bibliotekę Standard? Możesz. Chcesz robić niebezpieczne rzuty wskaźnikowe? Możesz. Chcesz naruszyć stałą poprawność? Możesz. Chcesz wymienić alokator pamięci? Możesz. Chcesz kopiować surową pamięć bez względu na jej typ? Jeśli naprawdę chcesz. Chcesz dziedziczyć po wielu implementacjach? To twój pogrzeb. Do diabła, możesz nawet uzyskać biblioteki śmieci, takie jak kolektor Boehm. Potem masz problemy, takie jak wydajność, która ściśle towarzyszy kontroli - im więcej kontroli ma programista, tym bardziej zoptymalizowany może stworzyć swój program.

Oto kilka rzeczy, które widziałem, przeprowadzając małe badania i rozmawiając z kilkoma osobami, które próbowały:

Ujednolicona hierarchia typów. Użytkownicy C ++ bardzo rzadko korzystają z dziedziczenia, większość programistów C ++ woli kompozycję, a typy powinny być łączone poprzez dziedziczenie tylko wtedy, gdy istnieje ku temu dobry powód. Pojęcie obiektu silnie narusza tę zasadę, łącząc każdy typ. Ponadto narusza jedną z podstawowych zasad C ++ - używasz tylko tego, co chcesz. Brak możliwości wyboru dziedziczenia po Object i związane z tym koszty są bardzo sprzeczne z tym, co C ++ oznacza jako język, jeśli chodzi o zapewnienie programiście kontroli nad jego programem.

Słyszałem o problemach z funkcjami i delegatami. Najwyraźniej D ma zarówno funkcje, jak i delegatów jako typy funkcji wywoływalnych w czasie wykonywania, i nie są one takie same, ale są one wymienne lub ... coś? Mój przyjaciel miał z nimi sporo problemów. Jest to zdecydowanie obniżenie wersji C ++, która właśnie ma std::functioni gotowe.

Masz kompatybilność. D nie jest szczególnie kompatybilny z C ++. Mam na myśli, że żaden język nie jest kompatybilny z C ++, spójrzmy prawdzie w oczy, z wyjątkiem C ++ / CLI, który jest rodzajem oszustwa, ale jako bariera wejścia, należy o tym wspomnieć.

Są jeszcze inne rzeczy. Na przykład po prostu przeczytaj wpis w Wikipedii.

import std.metastrings;
pragma(msg, Format!("7! = %s", fact_7));
pragma(msg, Format!("9! = %s", fact_9));

printfjest jedną z najbardziej niebezpiecznych funkcji, jakie kiedykolwiek wymyślono, w tej samej rodzinie, co duże problemy, jak getsze starej biblioteki C Standard. Jeśli szukasz tego w Stack Overflow, znajdziesz wiele, wiele pytań związanych z jego niewłaściwym użyciem. Zasadniczo printfjest to naruszenie SUSZENIA- podajesz typ w ciągu formatu, a następnie podajesz go ponownie, gdy podasz argument. Naruszenie DRY, gdy źle się pomylisz, zdarzają się bardzo złe rzeczy - powiedzmy, jeśli zmieniłeś typedef z 16-bitowej liczby całkowitej na 32-bitową. Nie można go w ogóle rozszerzyć - wyobraź sobie, co by się stało, gdyby wszyscy wymyślili własne specyfikatory formatu. Iostreamy w C ++ mogą być powolne, a ich wybór operatora może nie być najlepszy, a ich interfejs może korzystać z pracy, ale są zasadniczo zagwarantowane, że są bezpieczne, a DRY nie jest naruszone i można je łatwo rozszerzyć. Tego nie można powiedzieć printf.

Bez wielokrotnego dziedziczenia. To nie jest sposób w C ++. Programiści C ++ oczekują, że będą mieć pełną kontrolę nad swoim programem, a język wymuszający to, czego nie można odziedziczyć, stanowi naruszenie tej zasady. Ponadto powoduje, że dziedziczenie (jeszcze bardziej) jest kruche, ponieważ jeśli zmienisz typ interfejsu na klasę, ponieważ chcesz zapewnić domyślną implementację lub coś takiego, nagle cały kod użytkownika zostanie uszkodzony. To nie jest dobra rzecz.

Innym przykładem jest stringi wstring. W C ++ jest już dość bolesna konieczność konwersji między nimi, i czy ta biblioteka obsługuje Unicode, a ta stara biblioteka C używa tylko const char*i trzeba pisać różne wersje tej samej funkcji w zależności od żądanego typu argumentu ciągu. Na przykład nagłówki Windows mają na przykład bardzo irytujące makra, aby poradzić sobie z problemem, który często może zakłócać twój własny kod. Dodanie dstringdo miksu tylko pogorszy sytuację, ponieważ teraz zamiast dwóch typów strun musisz zarządzać trzema. Posiadanie więcej niż jednego typu łańcucha zwiększy bóle konserwacyjne i wprowadzi powtarzalny kod dotyczący łańcuchów.

Scott Meyers pisze:

D jest językiem programowania stworzonym, aby pomóc programistom sprostać wyzwaniom współczesnego oprogramowania. Czyni to poprzez wspieranie modułów połączonych ze sobą za pomocą precyzyjnych interfejsów, federacji ściśle zintegrowanych paradygmatów programowania, wymuszonej izolacji językowej wątków, bezpieczeństwa typu modułowego, wydajnego modelu pamięci i innych.

Wymuszona przez język izolacja wątków nie jest plusem. Programiści C ++ oczekują pełnej kontroli nad swoimi programami, a język wymuszający coś zdecydowanie nie jest tym, co zalecił lekarz.

Wspomnę również o manipulacji ciągami w czasie kompilacji. D ma zdolność interpretowania kodu D w czasie kompilacji. To nie jest plus. Rozważ ogromne bóle głowy spowodowane stosunkowo ograniczonym preprocesorem C, dobrze znanym przez wszystkich doświadczonych programistów C ++, a następnie wyobraź sobie, jak bardzo ta funkcja będzie nadużywana. Możliwość tworzenia kodu D w czasie kompilacji jest świetna, ale powinna być semantyczna , a nie składniowa.

Ponadto możesz spodziewać się pewnego odruchu. D ma wyrzucanie elementów bezużytecznych, które programiści C ++ będą kojarzyli z takimi językami, jak Java i C #, które są w filozofii wprost przeciwstawne, a podobieństwa syntaktyczne przywołają ich również na myśl. Niekoniecznie jest to obiektywnie uzasadnione, ale z pewnością należy to odnotować.

Zasadniczo nie oferuje tak wiele, że programiści C ++ nie mogą tego zrobić. Może łatwiej napisać silni metaprogram D, ale może już pisać czynnikowymi metaprograms w C ++. Może D ty może napisać kompilacji ray-tracer, ale nikt tak naprawdę nie chce zrobić, że tak. W porównaniu z podstawowymi naruszeniami filozofii C ++, to, co możesz zrobić w D, nie jest szczególnie godne uwagi.

Nawet jeśli te rzeczy są tylko problemami na powierzchni, to jestem prawie pewien, że fakt, że na powierzchni D wcale nie wygląda jak C ++, jest prawdopodobnie dobrym powodem, dla którego wielu programistów C ++ nie migruje do D. Być może D sam musi wykonać lepszą pracę, reklamując się.


9
@DeadMG: Jest to w 100% niepoprawne i nie ma sensu mówić, że to zdecydowanie obniżenie wersji C ++, które właśnie ma std::functioni gotowe. Dlaczego? Ponieważ masz na przykład wskaźniki funkcji. Jest dokładnie tak samo w „funkcjach” D: D są wskaźniki funkcji, a „delegaci” D są tacy sami jak C ++ std::function(z wyjątkiem tego, że są wbudowane). Nigdzie nie ma żadnej „obniżki” - a między nimi jest zgodność 1: 1, więc nie powinno to być mylące, jeśli znasz C ++.
Mehrdad

10
@Mark Trapp: Muszę przyznać, że nie do końca rozumiem twoje stanowisko na ten temat - nie można wykorzystywać komentarzy do komentowania odpowiedzi?
klickverbot

6
@Mark Trapp: Chodzi mi o to, że większość komentarzy tutaj nie była przestarzała (meta dyskusja, którą podłączyłeś, dotyczy konkretnie sugestii, które zostały już uwzględnione w oryginalnym poście), ale wskazała na nieścisłości faktyczne w poście, które są nadal obecne .
klickverbot

7
Uwaga na temat formatu: funkcja formatu D jest bezpieczna dla typów (rozwiązuje problemy związane z bezpieczeństwem / przepełnieniem) i nie narusza DRY, ponieważ ciąg formatu określa tylko sposób formatowania argumentów, a nie ich typy. Jest to możliwe dzięki bezpiecznym wariantom maszyn typu D. Dlatego przynajmniej ten zarzut jest całkowicie nieważny.
Justin W

17
@ Mark: Niezależnie od aktualnych zasad ich dotyczących, uważam za głupie i utrudniające usuwanie dyskusji na temat komentarzy . Myślę, że w tej odpowiedzi odbyły się obszerne dyskusje (którymi jestem teraz zainteresowany), ale nie jestem pewien i nie mam sposobu, aby się tego dowiedzieć. Ten pokój, do którego linkujesz, ma ponad 10 000 wiadomości i nie mam szans na znalezienie dyskusji, o której pamiętam, że się odbyła, ale nie pamiętam jej treści. Dyskusje na temat tej odpowiedzi należą tutaj, do tej odpowiedzi , a nie do jakiegoś pokoju rozmów, gdzie mogą być mieszane w dyskusjach na temat seksu, narkotyków i rock'n'rolla.
sbi

1

Jedną z rzeczy, które doceniam w C ++, jest możliwość udokumentowania argumentu funkcji lub zwrócenia wartości jako odwołania do C ++ zamiast wskaźnika, co oznacza implikację przyjęcia nullwartości innej niż wartość.

Wersja D:

class A { int i; }

int foo(A a) {
    return a.i; // Will crash if a is null
}

int main() {
    A bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    return foo(bar);
}

Wersja C ++:

class A { int i; };

int foo(A& a) {
    return a.i; // Will probably not crash since
                // C++ references are less likely
                // to be null.
}

int main() {
    A* bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    // Hm.. I have to dereference the bar-pointer
    // here, otherwise it wont compile.  Lets add
    // a check for null before.
    if (bar)
        return foo(*bar);
    return 0;
}

Aby być uczciwym, możesz bardzo zbliżyć się do C ++, przekształcając Ago w D structi oznaczając foo()-argument jako a ref(klasy to typy referencyjne, a struktury to typy wartości w D, podobne do C #).

Uważam, że NonNullablezamiast tego istnieje plan stworzenia szablonu dla klas jako standardowej biblioteki D. Mimo to lubię zwięzłość w Type&porównaniu z NonNullable(Type), i wolałbym, aby domyślna była wartość nullable (renderowanie czegoś takiego jak Typei Nullable(Type)). Ale jest już za późno, żeby to zmienić dla D, a teraz odpływam od tematu.


3
Zarówno argumenty funkcji, jak i zwracane wartości w D można oznaczyć za pomocą, refaby dać taki sam efekt jak w C ++ &. Jedną z głównych różnic jest to, że refnie potrwa to tymczasowo, nawet jeśli tak jest const.
Jonathan M. Davis,

Podoba mi się sposób, w jaki zwracanie odniesień do zmiennych lokalnych jest zabronione w D, nie wiedziałem o tym, dopóki nie przeczytałem twojego komentarza. Ale nadal możesz zwrócić nielokalne odwołanie zerowe, nie myśląc o tym w sposób, w którym operator dereferencji C zmusi cię do myślenia.
lumor

Mylisz rzeczy. Klasy są zawsze referencjami, i to jest odrębne od ref. Odnośniki w D są jak odniesienia w Javie. Są zarządzanymi wskaźnikami. Przekazywanie lub zwracanie przez referencję jest jak przekazywanie lub zwracanie za pomocą & w C ++. Przekazywanie odwołania do klasy przez odwołanie jest jak przekazywanie wskaźnika w C ++ za pomocą & (np. A * i). Klasy nie idą na stos. Tak, NonNullable umożliwiłoby odwołanie do klasy, które z pewnością miało wartość inną niż null, ale jest to całkowicie odrębne od ref. To, co próbujesz zrobić w kodzie C ++, nie działa w D, ponieważ klasy nie idą na stos. Struktury robią.
Jonathan M Davis,

1
Tak więc, posiadanie odwołania do klasy, które nie jest nullabe, byłoby fajne, ale C ++ udaje się zrobić to, co pokazujesz, ponieważ pozwala klasom znajdować się na stosie i pozwala na odsyłanie wskaźników. A gdy może dereference wskaźników w D, klasy są referencje, a nie wskaźniki, więc nie można dereference nich. Ponieważ nie możesz umieścić ich na stosie i nie możesz się z nich wywnioskować, nie ma możliwości wbudowania w D klasy, która nie może mieć wartości zerowej. Jest to strata, ale NonNullable to naprawi, a korzyści z rozdzielenia struktur i klas są generalnie większe.
Jonathan M. Davis,

2
Odwołania w C ++ nie mogą być zerowe według standardu językowego (powiedzenie „prawdopodobnie nie będzie zerowe” jest niepoprawne, ponieważ nie może być zerowe). Chciałbym, aby istniał sposób na wyłączenie wartości null jako prawidłowej wartości dla klasy.
jsternberg,

1

Najważniejszą rzeczą, jaką C ++ „robi lepiej” niż D, jest połączenie ze starszymi bibliotekami . Różne silniki 3D, OpenCL i podobne. Ponieważ D jest nowy, ma znacznie mniejszą liczbę różnych bibliotek do wyboru.

Inną ważną różnicą między C ++ i D jest to, że C ++ ma wielu niezależnych finansowo dostawców, ale od 2014 roku D ma praktycznie tylko jednego , dwuosobowego zespołu, który go stworzył. Interesujące jest to, że „zasada drugiego źródła”, która mówi, że projekty nigdy nie powinny zależeć od technologii, komponentów, które mają tylko jednego, jednego dostawcę, wydaje się obowiązywać nawet dla oprogramowania.

Dla porównania, pierwsza wersja interpretera Ruby została napisana przez wynalazcę Ruby, Yukihiro Matsumoto, ale główny nurt z 2014 roku, tłumacz z Ruby, został napisany praktycznie od zera przez innych ludzi. Dlatego Ruby można postrzegać jako język, który ma więcej niż jednego niezależnego finansowo dostawcę. Z drugiej strony D może być niesamowitą technologią, ale zależy to od kilku programistów, którzy ją rozwijają.

Historia Java pokazuje, że nawet jeśli technologia, w tym przypadku Java, ma świetny, ale pojedynczy, finansujący, istnieje duże ryzyko, że technologia zostanie zasadniczo zrzucona, niezależnie od ogromnej bazy użytkowników korporacyjnych. Cytat z Apache Software Foundation , gdzie EC oznacza „Komitet Wykonawczy”:

Oracle dostarczyło do EC zapytanie o licencję Java SE 7 i licencję, które są wewnętrznie sprzeczne, poważnie ograniczają dystrybucję niezależnych implementacji specyfikacji, a co najważniejsze, zabraniają dystrybucji niezależnych implementacji specyfikacji Open Source.

Historycznie można powiedzieć, że aplety Java miały przyspieszone sprzętowo płótno 3D na wiele lat przed opracowaniem HTML5 WebGL. Problem z szybkością uruchamiania apletów Java mógłby zostać rozwiązany, gdyby Java była projektem społecznościowym, ale menedżerowie jedynego podmiotu finansującego Javę, Sun Microsystems, nie uważali za wystarczająco ważne, aby naprawić implementację Java. Rezultat końcowy: płótno HTML5 wielu dostawców jako „replika biedaka” frameworku Java GUI (Swing itp.). Co ciekawe, po stronie serwera język programowania Python ma te same zalety, które obiecał Java: pisz raz, uruchamiaj na każdym serwerze, niezależnie od sprzętu, pod warunkiem, że aplikacja Python nie jest skompilowana do kodu maszynowego. Python jest mniej więcej tak stary / młody jak Java, ale w przeciwieństwie do Javy jest to „

Podsumowanie:

Podczas oceny technologii do użytku produkcyjnego najważniejszymi właściwościami technologii są ludzie, którzy ją rozwijają, proces społeczny, w którym odbywa się rozwój, oraz liczba niezależnych finansowo zespołów programistycznych.

To, czy korzystniejsze jest zastosowanie technologii T1 w porównaniu z technologią T2, zależy od dostawców technologii oraz od tego, czy technologia T1 pozwala na rozwiązanie problemów związanych z projektem taniej niż T2. Na przykład, jeśli problem pojedynczego dostawcy zostałby zignorowany, wówczas dla systemów informatycznych Java byłaby „lepszą” technologią niż C ++, ponieważ pliki binarne Java nie wymagają ponownej kompilacji przy wdrażaniu na nowym sprzęcie i pracach programistycznych związanych z zarządzaniem pamięcią jest mniejszy dla Javy niż dla C ++. Projekty tworzone od zera, np. Projekty, które nie zależą od innych bibliotek, mogą być tańsze w D niż C ++, ale z drugiej strony C ++ ma więcej niż jednego dostawcę i dlatego jest mniej ryzykowne w dłuższej perspektywie . (Przykład Java, w którym Sun Microsystems był prawie OK,

Możliwe obejście niektórych ograniczeń C ++

Jednym z możliwych obejść niektórych ograniczeń C ++ jest użycie wzorca projektowego, w którym początkowe zadanie jest dzielone na części i elementy są „sortowane” (klasyfikowane, grupowane, dzielone, inne-miłe-słowa-za- to samo) do 2 klas: kontroluj zadania związane z logiką , w których wzorce dostępu do pamięci nie pozwalają na lokalizację; zadania podobne do przetwarzania sygnałów , w których lokalizacja jest łatwo osiągalna. Zadania „podobne” przetwarzania sygnałów mogą być realizowane jako zestaw stosunkowo uproszczonych programów konsolowych. Zadania związane z logiką sterowania są umieszczone w jednym skrypcie napisanym w Ruby, Pythonie lub w innym miejscu, w którym wygoda tworzenia oprogramowania ma wyższy priorytet niż szybkość.

Aby uniknąć kosztownej inicjalizacji procesu systemu operacyjnego i kopiowania danych między procesami systemu operacyjnego, zestaw małych aplikacji konsoli C ++ można zaimplementować jako pojedynczy program C ++ uruchamiany jako „serwlet” przez Ruby / Python / itp. scenariusz. Ruby / Python / etc. skrypt zamyka serwlet przed wyjściem. Komunikacja między „serwletem” a Ruby / Python / etc. skrypt działa na potoku o nazwie Linux lub innym podobnym mechanizmie.

Jeśli początkowe zadanie nie daje się łatwo podzielić na części, które można zaklasyfikować do dwóch wyżej wymienionych klas, wówczas można spróbować ponownie sformułować problem, aby początkowe zadanie uległo zmianie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.