C'è qualche motivo per usare C ++ invece di C, Perl, Python, ecc.? [chiuso]


164

Come sviluppatore Linux (lato server), non so dove e perché dovrei usare C ++.

Quando vado a esibirsi, la prima e l'ultima scelta è C.

Quando "performance" non è il problema principale, i linguaggi di programmazione come Perl e Python sarebbero buone scelte.

Quasi tutte le applicazioni open source che conosco in quest'area sono state scritte in C, Perl, Python, Bash script, AWK o persino PHP, ma nessuno usa C ++.

Non sto discutendo di altre aree come la GUI o le applicazioni web, sto solo parlando di Linux, CLI e demoni.

C'è qualche motivo soddisfacente per usare il C ++?


5
Considero solo C ++ a causa di STL.
dan_waterworth,

46
Quindi qualcosa che può essere fatto usando C, perl e python insieme può essere fatto usando solo C ++. E ti stai chiedendo perché usare C ++?
Manoj R

36
«Quando ho intenzione di esibirmi, la prima e l'ultima scelta è C.» sì certo: D È un'affermazione non dimostrata e banalmente sbagliata.
deadalnix,

16
@deadalnix: non lo direi. Il C ++ ha regole complesse che potrebbero ritorcersi contro l'ottimizzatore, perché non è autorizzato a fare alcune cose. Ed è semplicissimo entrare nei killer invisibili delle prestazioni. È praticamente assiomatico, e quindi vero: D Ancora in realtà il codice C ++ a volte sarà più veloce perché utilizzerai algoritmi e strutture di dati più efficaci, e nessuno ottimizzerà comunque il codice C. Quindi, se fatto correttamente, C ++ è C più sicuro ed efficace, e dovresti scegliere C ++ su C quando non ci sono problemi di compatibilità o requisiti per un software di disponibilità al 100%.
Coder

4
Il miglior motivo, non considerato nelle risposte postate, è direttamente correlato alla domanda di OP. DEPENDANCIES !!!!, Non che il tuo sistema medio manchi delle librerie c ++, ma un sistema incorporato potrebbe non averle disponibili. L'unico modo per ottenere il tuo programma in ogni sistema è scrivere il tuo programma in C. normale. Tutto il resto sta solo discutendo sul perché dovresti, o meno rappresentato, non usare C ++. Niente di tutto ciò affronta il motivo per cui il C ++ non viene utilizzato più spesso, e indipendentemente dal merito, la ragione è la dipendenza .... O e anche il famoso c ++ rant di Linus.
JM Becker,

Risposte:


308

Quando ho intenzione di esibirmi, la prima e l'ultima scelta è C.

Ed è qui che dovresti eseguire il backup. Ora, non posso, a tutti , parlare di sviluppo del server. Forse non c'è davvero alcun motivo convincente per preferire il C ++ rispetto alle alternative.

Ma in generale, la ragione per usare il C ++ piuttosto che altri linguaggi è proprio la prestazione. La ragione di ciò è che C ++ offre un mezzo di astrazione che, a differenza di tutti gli altri linguaggi che conosco, non ha costi generali di esecuzione in fase di esecuzione.

Ciò consente di scrivere codice molto efficiente che ha ancora un livello di astrazione molto elevato.

Considera le solite astrazioni: funzioni virtuali, puntatori a funzione e linguaggio PIMPL. Tutti questi si basano sull'indirizzamento indiretto che è in fase di esecuzione risolto dall'aritmetica del puntatore. In altre parole, comporta un costo in termini di prestazioni (per quanto piccolo possa essere).

Il C ++, d'altra parte, offre un meccanismo indiretto che non comporta costi (di prestazione): i template. (Questo vantaggio viene pagato con un tempo di compilazione (talvolta enormemente aumentato).

Considera l'esempio di una funzione di ordinamento generica.

In C, la funzione qsortprende un puntatore a funzione che implementa la logica in base alla quale gli elementi sono ordinati l'uno rispetto all'altro. La Arrays.sortfunzione di Java è disponibile in diverse varianti; uno di li ordina oggetti arbitrari e richiede un Comparatoroggetto viene passato al metodo che funziona come il puntatore a funzione in C di qsort. Ma ci sono molti altri sovraccarichi per i tipi Java "nativi". E ognuno di essi ha una propria copia del sortmetodo: un'orribile duplicazione del codice.

Java illustra qui una dicotomia generale: o si ha la duplicazione del codice o si incorre in un sovraccarico di runtime.

In C ++, la sortfunzione funziona in modo molto simile qsorta C, con una piccola ma fondamentale differenza: il comparatore che viene passato alla funzione è un parametro template . Ciò significa che la sua chiamata può essere integrata . Non è necessaria alcuna indiretta per confrontare due oggetti. In un circuito stretto (come nel caso qui) questo può effettivamente fare una differenza sostanziale.

Non sorprende che la sortfunzione C ++ superi C sortanche se l'algoritmo sottostante è lo stesso. Ciò è particolarmente evidente quando la logica di confronto effettiva è economica.

Ora, sto non dicendo che C ++ è a priori più efficiente di C (o altri linguaggi), né che, a priori, offre un'astrazione più elevato. Ciò che offre è un'astrazione che è molto alta e incredibilmente economica allo stesso tempo, quindi spesso non è necessario scegliere tra codice efficiente e riutilizzabile.


16
Ora so abbastanza su C ++ per sapere se sei esatto o sbagliato. Ma vuoi anche aggiungere che hai ricevuto solo 1 downvote, quindi rilassati. Questa è Internet e avvengono downvotes. Ottima risposta però se è tecnicamente valida!
Chris,

46
nessun sovraccarico di prestazioni in fase di esecuzione - non è sempre vero. Se guardi le implementazioni vettoriali STL vedrai che non sfruttano il vantaggio di usare realloc () (non possono farlo a causa di puntatori, lunga storia) mentre tutti i linguaggi di livello superiore che conosco possono e usano realloc ( ) in impl vettoriale. Questo è solo un esempio del fatto che non è così ovvio e tutto in bianco e nero.
Mojuba,

19
@Jaroslaw, @Steve: ma lo stesso (= code bloat, istruzioni cache mancate) è vero per il codice ottimizzato a mano che viene adattato per ogni tipo di dati (vedere le varie Arrays.sortimplementazioni di Java ). Solo tu perdi il vantaggio dell'alta astrazione. Questo non è uno svantaggio specifico dei modelli, è uno svantaggio della duplicazione del codice in generale. Inoltre, questo tende a non avere importanza poiché in loop stretti, di solito è sempre lo stesso codice che viene caricato.
Konrad Rudolph,

18
@Jaroslaw: la cosa divertente della cache delle istruzioni è che è una cache . Cioè, non tenta di memorizzare tutto , solo il codice utilizzato di recente . I modelli potrebbero generare un sacco di codice simile per tipi diversi (un vector.push_backper vector<int>e un altro per vector<float>, ma mentre si lavora con un vector<int>, ci sono pochi motivi per cui il vector<float>codice dovrebbe essere nella cache delle istruzioni. Quindi non vedo come questo abbia davvero importanza. l' istanza del modello individuale è altamente ottimizzata e in genere più compatta delle implementazioni
generali

29
@ Steve314: Quello che chiami "gonfio" è ciò che viene fatto manualmente per C e Java. In C ++, può essere automatizzato e i compilatori possono essere intelligenti quanto i venditori osano farli per evitare il gonfiamento. Se devo decidere se essere lento (come in C) o usare un codice duplicato (come in Java), avere il compilatore che esegue la duplicazione (e forse essere furbo) sembra piuttosto buono, no?
sbi,

166

Vedo troppi programmatori C che odiano il C ++. Mi ci è voluto un po 'di tempo (anni) per capire lentamente cosa è buono e cosa è male. Penso che il modo migliore per esprimere sia questo:

Meno codice, nessun sovraccarico di runtime, più sicurezza.

Meno codice scriviamo, meglio è. Questo diventa rapidamente chiaro in tutti gli ingegneri che lottano per l'eccellenza. Risolvi un bug in un posto, non in molti: esprimi un algoritmo una volta e lo riutilizzi in molti luoghi, ecc. I greci hanno persino un modo di dire, fatto risalire agli antichi spartani: "dire qualcosa in meno parole, significa che sei saggio al riguardo ". E il fatto è che, se usato correttamente , C ++ ti permette di esprimerti in un codice molto meno di C, senza costare la velocità di runtime, pur essendo più sicuro (cioè catturando più errori in fase di compilazione) di quanto lo sia C.

Ecco un esempio semplificato dal mio renderer : quando si interpolano i valori dei pixel attraverso la linea di scansione di un triangolo. Devo partire da una coordinata X x1 e raggiungere una coordinata X x2 (da sinistra a destra di un triangolo). E attraverso ogni passaggio, attraverso ogni pixel che passo, devo interpolare i valori.

Quando interpolo la luce ambientale che raggiunge il pixel:

  typedef struct tagPixelDataAmbient {
      int x;
      float ambientLight;
  } PixelDataAmbient;

  ...
  // inner loop
  currentPixel.ambientLight += dv;

Quando interpolo il colore (chiamato ombreggiatura "Gouraud", in cui i campi "rosso", "verde" e "blu" sono interpolati da un valore di passo per ogni pixel):

  typedef struct tagPixelDataGouraud {
      int x;
      float red;
      float green;
      float blue;  // The RGB color interpolated per pixel
  } PixelDataGouraud;

  ...
  // inner loop
  currentPixel.red += dred;
  currentPixel.green += dgreen;
  currentPixel.blue += dblue;

Quando eseguo il rendering in ombreggiatura "Phong", non interpolo più un'intensità (luce ambientale) o un colore (rosso / verde / blu) - Interpolo un vettore normale (nx, ny, nz) e ad ogni passo, devo ri -calcolare l'equazione dell'illuminazione, in base al vettore normale interpolato:

  typedef struct tagPixelDataPhong {
      int x;
      float nX;
      float nY;
      float nZ; // The normal vector interpolated per pixel
  } PixelDataPhong;

  ...
  // inner loop
  currentPixel.nX += dx;
  currentPixel.nY += dy;
  currentPixel.nZ += dz;

Ora, il primo istinto dei programmatori C sarebbe "diamine, scrivere tre funzioni che interpolano i valori e chiamarli in base alla modalità impostata". Prima di tutto, questo significa che ho un problema di tipo: con cosa lavoro? I miei pixel PixelDataAmbient sono? PixelDataGouraud? PixelDataPhong? Oh, aspetta, dice l'efficiente programmatore C, usa un sindacato!

  typedef union tagSuperPixel {
      PixelDataAmbient a;
      PixelDataGouraud g;
      PixelDataPhong   p;
  } SuperPixel;

..e poi hai una funzione ...

  RasterizeTriangleScanline(
      enum mode, // { ambient, gouraud, phong }
      SuperPixel left,
      SuperPixel right)
  {
      int i,j;
      if (mode == ambient) {
          // handle pixels as ambient...
          int steps = right.a.x - left.a.x;
          float dv = (right.a.ambientLight - left.a.ambientLight)/steps;
          float currentIntensity = left.a.ambientLight;
          for (i=left.a.x; i<right.a.x; i++) {
              WorkOnPixelAmbient(i, dv);
              currentIntensity+=dv;
          }
      } else if (mode == gouraud) {
          // handle pixels as gouraud...
          int steps = right.g.x - left.g.x;
          float dred = (right.g.red - left.g.red)/steps;
          float dgreen = (right.g.green - left.a.green)/steps;
          float dblue = (right.g.blue - left.g.blue)/steps;
          float currentRed = left.g.red;
          float currentGreen = left.g.green;
          float currentBlue = left.g.blue;
          for (j=left.g.x; i<right.g.x; j++) {
              WorkOnPixelGouraud(j, currentRed, currentBlue, currentGreen);
              currentRed+=dred;
              currentGreen+=dgreen;
              currentBlue+=dblue;
          }
...

Senti che il caos sta scivolando dentro?

Prima di tutto, è sufficiente un errore di battitura per bloccare il mio codice, poiché il compilatore non mi fermerà mai nella sezione "Gouraud" della funzione, per accedere effettivamente a ".a". valori (ambientali). Un bug non rilevato dal sistema di tipo C (cioè durante la compilazione) indica un bug che si manifesta in fase di esecuzione e richiederà il debug. Hai notato che left.a.greenaccedo al calcolo di "dgreen"? Il compilatore sicuramente non te lo ha detto.

Quindi, c'è ripetizione ovunque: il forloop è lì per tutte le volte che ci sono modalità di rendering, continuiamo a fare "destra meno sinistra divisa per passi". Brutto e soggetto a errori. Hai notato che ho confrontato usando "i" nel loop di Gouraud, quando avrei dovuto usare "j"? Il compilatore è di nuovo silenzioso.

Che dire dell'if / else / ladder per le modalità? Cosa succede se aggiungo una nuova modalità di rendering in tre settimane? Ricorderò di gestire la nuova modalità in tutto il "if mode ==" in tutto il mio codice?

Ora confronta la bruttezza sopra, con questo set di strutture C ++ e una funzione template:

  struct CommonPixelData {
      int x;
  };
  struct AmbientPixelData : CommonPixelData {
      float ambientLight;
  };
  struct GouraudPixelData : CommonPixelData {
      float red;
      float green;
      float blue;  // The RGB color interpolated per pixel
  };
  struct PhongPixelData : CommonPixelData {
      float nX;
      float nY;
      float nZ; // The normal vector interpolated per pixel
  };

  template <class PixelData>
  RasterizeTriangleScanline(
      PixelData left,
      PixelData right)
  {
      PixelData interpolated = left;
      PixelData step = right;
      step -= left;
      step /= int(right.x - left.x); // divide by pixel span
      for(int i=left.x; i<right.x; i++) {
          WorkOnPixel<PixelData>(interpolated);
          interpolated += step;
      }
  }

Ora guarda questo. Non creiamo più una zuppa di tipo sindacale: abbiamo tipi specifici per ogni modalità. Riutilizzano le loro cose comuni (il campo "x") ereditando da una classe base ( CommonPixelData). E il template rende il compilatore CREATE (ovvero generare codice) le tre diverse funzioni che avremmo scritto in C, ma allo stesso tempo, essendo molto severi sui tipi!

Il nostro ciclo nel modello non può andare in giro e accedere a campi non validi - il compilatore abbaia se lo facciamo.

Il modello esegue il lavoro comune (il ciclo, aumentando di "passo" in ogni momento) e può farlo in un modo che semplicemente NON può causare errori di runtime. L'interpolazione per ogni tipo ( AmbientPixelData, GouraudPixelData, PhongPixelData) è fatto con il operator+=()che l'aggiungeremo nei struct - che fondamentalmente dettano come ogni tipo viene interpolato.

E vedi cosa abbiamo fatto con WorkOnPixel <T>? Vogliamo fare lavori diversi per tipo? Chiamiamo semplicemente una specializzazione modello:

void WorkOnPixel<AmbientPixelData>(AmbientPixelData& p)
{
    // use the p.ambientLight field
}


void WorkOnPixel<GouraudPixelData>(GouraudPixelData& p)
{
    // use the p.red/green/blue fields
}

Cioè - la funzione da chiamare, viene decisa in base al tipo. In fase di compilazione!

Per riformularlo di nuovo:

  1. minimizziamo il codice (tramite il modello), riutilizzando parti comuni,
  2. non usiamo brutti hack, manteniamo un sistema di tipi rigoroso, in modo che il compilatore possa controllarci in ogni momento.
  3. e soprattutto: nulla di ciò che abbiamo fatto ha QUALSIASI impatto di runtime. Questo codice verrà eseguito SOLO più velocemente dell'equivalente codice C - in effetti, se il codice C utilizzava i puntatori a funzione per chiamare le varie WorkOnPixelversioni, il codice C ++ sarà più veloce di C, perché il compilatore incorporerà la WorkOnPixelspecializzazione del modello specifico del tipo chiamata!

Meno codice, nessun sovraccarico di runtime, più sicurezza.

Questo significa che il C ++ è l'essere tutti e terminare tutte le lingue? Ovviamente no. Devi ancora misurare i compromessi. Le persone ignoranti useranno C ++ quando avrebbero dovuto scrivere uno script Bash / Perl / Python. I neofiti del C ++ in grado di innescare creeranno classi annidate profonde con ereditarietà multipla virtuale prima che tu possa fermarle e inviarle a pacchetti. Utilizzeranno la complessa meta-programmazione Boost prima di rendersi conto che ciò non è necessario. Essi utilizzano ancora char*, strcmpe le macro, invece di std::stringe modelli.

Ma questo non dice altro che ... guarda con chi lavori. Non esiste un linguaggio per proteggerti dagli utenti incompetenti (no, nemmeno Java).

Continua a studiare e ad usare il C ++ - semplicemente non sovrascrivere.


18
+1 per "no, nemmeno Java" :)
Nathan Osman,

53
+1 per l'esempio. Era un post lungo, ma il confronto tra codice C e C ++ è impressionante.
paercebal,

E questo, onorevoli colleghi, è per questo che esiste il lex / yacc. Stesso ragionamento, non ho mai realizzato che parti di c ++ rientrassero nella stessa filosofia di generazione del codice. Dovrò rivederlo qualche volta.
Spencer Rathbun,

2
Ho scritto un sacco di codice di rendering 2D (più di un decennio fa) e ho riscontrato questo problema durante il porting da C a C ++: come si definisce una struttura di pixel, se la linea di scansione è composta da pixel da 1 bit (8 pixel in un byte)? E quando la linea di scansione è composta da byte R, G e B (3 byte per pixel)? E quando hai tre buffer separati per R, G e B? Conosci la risposta: il C ++ non ti è di alcun aiuto e insistere sull'uso dei modelli ti farà perdere un sacco di ottimizzazioni di spazio e tempo
Walter Tross,

Perché usi i template in C ++ per questo? Il tuo metodo dichiara un parametro della classe base, quindi dal mio punto di vista [programmatore C #] sembra che potresti semplicemente passare l'istanza di tipo derivato al parametro di tipo base. Non conosco il C ++, potresti spiegarmi per favore?
Vlad

79

RAII per il bambino vincente.

Scherzi a parte, la distruzione deterministica in C ++ rende il codice molto più chiaro e sicuro senza alcun sovraccarico.


20
"C ++: l'unica opzione seriamente deterministica. Chiedi al tuo medico oggi."
Kyle Strand,

2
Follow-up: Rust è ora un contendente in questo campo. Vedi un esempio RAII di base e la documentazione sui metodi distruttori di Rust .
Kyle Strand,

1
C sarà deterministico, ma richiede più lavoro per assicurarsi che accada effettivamente quando si usa la memoria malloc ed
Baldrickk,

1
@Baldrickk in C devi scrivere il codice di pulizia ovunque usi una risorsa. In C ++, lo scrivi una volta , nella definizione della risorsa. Sia C che Java soffrono di bug "risorse utilizzate dopo l'eliminazione" e "perdite delle risorse", poiché la pulizia non è automatica . La memoria non è l'unica risorsa.
Caleth,

70

C'è qualche motivo soddisfacente per usare il C ++?

  1. Modelli e STL. Ti permetti di scambiare un po 'di tempo di costruzione (e alcuni messaggi di errore potenzialmente incomprensibili) con molti utili strumenti di astrazione e di risparmio di manodopera, senza alcun apprezzabile risultato di runtime (sebbene l'impronta binaria possa essere leggermente più grande).

    Ci vuole un po 'per avvolgere la testa (mi ci sono voluti un paio d'anni prima che scattasse), ma una volta che lo fai può rendere la vita molto più semplice.

  2. L'elaborazione del testo in C ++ è un ordine di grandezza meno doloroso di quanto non lo sia in C.


35
+1 per l'elaborazione del testo, che ho completamente dimenticato nella mia risposta.
Konrad Rudolph,

8
Heh ho trovato particolarmente dolorosa l'elaborazione del testo rispetto a dire Python ..
Nils

7
Boost è l'unica ragione per cui utilizzo ancora C ++.
Ferruccio,

33
@Nils: su una scala da 1 a dolorosa, l'elaborazione del testo in C ++ è decisamente peggiore rispetto a linguaggi più moderni come Python. È solo che l'elaborazione del testo in C definisce il dolore. Se la scelta è tra C e C ++ per quella particolare applicazione, allora C ++ vince facilmente.
John Bode,

8
Non so perché le persone abbiano tali difficoltà con cose come l'elaborazione del testo in C / C ++. Basta usare una libreria o scrivere la tua. Dopo aver scritto le funzioni di basso livello (dolore una tantum), ottieni prestazioni eccezionali, codice stretto e maggiore flessibilità. Sì, userò Python per utility da riga di comando veloci / sporche ma per codice di produzione serio è C / C ++.

41

Sì.

Se stai cercando l'efficienza eseguibile, sei in C o C ++, quindi mi concentrerò su quello.

Anche prima che i modelli fossero comuni, ho preferito usare C ++ su C per i tipi di file eseguibili discussi già a metà degli anni '90 per due ragioni molto semplici: polimorfismo degli oggetti e RAII .

Ho usato oggetti C ++ polimorfici per tutti i tipi di cose interessanti. Ad esempio, stavo lavorando su un sistema Linux incorporato con sovrapposizioni di frame buffer su CPU ARM OMAP e XScale. Le due architetture hardware hanno diverse funzionalità di overlay con API molto diverse. Ho usato una classe di base virtuale "Overlay" comune per esporre una vista idealizzata degli overlay, quindi ho scritto le classi "OmapOverlay" e "XScaleOverlay" che sono state istanziate in modo appropriato in fase di esecuzione, a seconda dell'architettura su cui il codice ha rilevato che era in esecuzione.

Per semplificare eccessivamente, RAII è l'idea di allocare risorse collegate a un oggetto durante il costruttore dell'oggetto, o forse più tardi nella vita dell'oggetto, e le risorse vengono deallocate o rilasciate nel distruttore dell'oggetto. È davvero bello in C ++, perché gli oggetti che sono variabili automatiche vengono distrutti quando escono dall'ambito. Per qualcuno che è ugualmente competente in C e C ++, è molto più facile evitare perdite di risorse e memoria in C ++. Inoltre non vedi molto codice C ++ con il meme C molto comune di un'etichetta alla fine di una funzione che precede un mucchio di chiamate a free(), e varie cose gotonel blocco funzione saltano lì.

Sono pienamente consapevole del fatto che puoi fare tutte queste cose con C: è solo molto più lavoro, molte più righe di codice e ciò che finisci è molto più brutto e spesso più difficile da capire. C'è un codice di polimorfismo attraverso gli interni del server X e, man, è fugace e strano e spesso difficile da rintracciare.

Inoltre lavoro molto con le tecnologie GNOME come GTK + e Clutter, tutte scritte in C usando il sistema GObject. GObject è come il sistema a oggetti C ++ con la bella copertina tolta e tutti i brutti interni esposti, e di solito richiede una mezza dozzina di righe di codice per fare ciò che farebbe una chiamata al metodo C ++ a una riga. Attualmente ne sto scrivendo alcuni ClutterActors, e mentre la matematica è davvero interessante, penso costantemente: "Tutto ciò sarebbe molto più succinto e comprensibile in C ++".

Spesso penso anche: "Sai, se stessi scrivendo questo in C ++ anziché in C, sarei fuori in salotto a guardare MythBusters con mia moglie invece di sedermi nel mio ufficio alle 21:00".


9
Posso davvero collegarmi a ciò che stai dicendo qui, in particolare 1) il punto su RAII e 2) il pensiero "Sai, se stavo scrivendo questo in C ++ invece di C ..." Faccio molto sviluppo di sistemi embedded e anche se il team è praticamente un tipo di negozio "C" o "C con classi", cerco davvero di incoraggiare RAII per cose come manipolazione di interruzioni, operazioni di mutex e traccia / registrazione (specialmente cose come attivare / disattivare l'I / O Linee). E la tua descrizione dei buffer di frame polimorfici mi ha ricordato il mio uso dei buffer di messaggi polimorfici in un sistema distribuito.
Radian,

29

C ++ è veloce quanto C (alcune cose sono più veloci, altre più lente) e offre astrazioni e organizzazione migliori. Le classi funzionano in modo simile ai tipi primitivi, consentendo di utilizzare grandi quantità di codice senza tenerne conto. Il sovraccarico dell'operatore e i modelli consentono di scrivere codice che funzioni meglio se le rappresentazioni dei dati cambiano. Le eccezioni possono consentire una più facile gestione degli errori. Il compilatore può essere usato per controllare più cose in fase di compilazione.

Il prezzo che paghi per questo è una curva di apprendimento abbastanza brutta, ed è più facile commettere errori sottili rispetto alla maggior parte delle altre lingue che conosco.

Quindi, non posso dire se varrebbe la pena impararlo per quello che stai facendo ora. Puoi certamente cavartela con combinazioni di Python o Perl e C, ma C ++ offre sia astrazione che prestazioni in un pacchetto difficile da abituare.


13
Non esiste un caso in cui C ++ sia più lento di C perché puoi sempre usare il modo C se è più veloce (e ti interessa).
Jack Aidley,

1
@JackAidley - Tranne il fatto che C ++ non supporta i parametri restrittivi e statici dell'array. E tranne che l'uso dello stile C ++ in un posto ti costringe a usarlo in altri posti.
martinkunev,

@martinkunev restrictè usato per fare esclusioni dall'ottimizzazione dell'aliasing, quindi come può aiutare a rendere le cose più veloci ? e che cos'è un "parametro array statico"? e in che modo lo "stile" influisce sulle prestazioni?
underscore_d

1
@underscore_d limitano le ottimizzazioni dei permessi, basate su una garanzia di non aliasing; i parametri di array statici consentono al compilatore di supporre che un argomento puntatore non sia NULL e che questo puntatore punti almeno a un determinato numero di elementi; la parola "stile" ha diversi significati e metterla fuori contesto cambia il suo significato - sto parlando di come, ad esempio, le eccezioni impongano l'uso di puntatori intelligenti.
martinkunev,

1
@martinkunev Hmm, quindi mi chiedo se un parametro di array statico abiliti qualcosa di funzionalmente diverso da un modello C ++ usando un T (&arr)[n]o std::array<T, n>- dovrà cercare questo più, dato che non ci sono molte informazioni là fuori. Questo ha senso sui puntatori intelligenti, sicuramente un buon esempio. Se codifichiamo su un campo di gioco uguale, non utilizzeremmo eccezioni, quindi non verrebbero sostenuti i costi potenziali ... tuttavia sospetto che potresti alludere a come, una volta che le biblioteche di terze parti entrano in scena, molte ipotesi sono a rischio.
underscore_d

27

Considero il C ++ un linguaggio degli anni '90, un linguaggio di un'epoca passata.

All'epoca era grande perché offriva costrutti e meccanismi linguistici di livello superiore a un costo inferiore in termini di prestazioni. Era lo strumento universale per lo sviluppo di tutto, dalle applicazioni della rubrica al software avionico, e questo ha ispirato la mania di OO. OOP ha risolto la fame e l'AIDS, e sì, biasimo il C ++ per aver cercato di farmi il lavaggio del cervello alla fine degli anni '90, quando ho iniziato a programmare che qualsiasi linguaggio non-OO non vale la pena imparare.

Ora che l'hardware è progredito così tanto e sono apparsi linguaggi più moderni e moderni, non riesco a vedere il C ++ che rimane una scelta rilevante per la maggior parte delle programmazioni applicative ad eccezione dei software a elevata intensità computazionale in cui è ancora necessaria un'astrazione (giochi, simulazioni fisiche, sistemi CAD, ecc. ). Anche quest'ultimo può essere evitato se si scrive un motore compatto e modulare in C e si dispone di una logica applicativa di livello superiore delegata a un linguaggio di script pulito.

Se devi scendere al metal usa C in modo sicuro e quando devi andare di alto livello, fallo in un linguaggio moderno che non pubblicizza l'incapsulamento mentre puoi modificare liberamente ogni byte tramite un puntatore.


11
Quindi non alterare i byte casuali usando i puntatori. Non è così difficile da evitare, non è vero?
David Thornley,

11
@Blagovest: sono d'accordo con te sulla complessità del C ++ e non lo userei mai per sostituire un linguaggio orientato agli oggetti. Ma nonostante la sua complessità vince ancora su C per me a causa dei suoi numerosi vantaggi enunciati in diverse risposte (astrazione, gestione delle risorse, gestione delle stringhe ...). In effetti, hai nominato alcune aree valide in cui il C ++ è ancora rilevante e dove è di gran lunga superiore a C.
Konrad Rudolph,

6
@Blagovest: ecco perché resto fuori dagli angoli bui. È più facile essere rapinati lì in C ++ rispetto a qualsiasi altra lingua che conosco. Usandolo, traggo vantaggio da RAII, una gestione della stringa molto migliore rispetto a C, le classi di modelli di tipo STL, le funzionalità OO e altri vantaggi che ha rispetto a C.
David Thornley,

24
@Blagovest: No, non lo fai. Ad esempio, ciò che hai menzionato non è sufficiente per raggiungere RAII e le classi di container hanno funzionalità che vanno oltre le semplici strutture di dati realizzate a mano. Se pensi che sia possibile, non hai mai imparato bene il C ++.
David Thornley,

5
@Jaroslaw Non riesco a capire perché le macchine multi-core mettano OOP nella tomba. Se intendi C ++, potrei vedere da dove vieni. OOP è un concetto fondamentale in molti linguaggi di programmazione moderni, in particolare linguaggi di alto livello. Anche C può essere OO, se lo programmate in quel modo. Non è conveniente come C ++ IMO.
Vedosity

21

Secondo Linus , no:

Quando ho guardato per la prima volta il codice sorgente di Git, due cose mi sono sembrate strane: 1. C puro invece di C ++. Non ho idea del perché. Per favore, non parlare di portabilità, è BS.

Sei pieno di cazzate.

Il C ++ è un linguaggio orribile. È reso più orribile dal fatto che molti programmatori scadenti lo usano, al punto che è molto più facile generare cazzate totali e assolute. Francamente, anche se la scelta di C non dovesse fare altro che tenere fuori i programmatori C ++, questo di per sé sarebbe un enorme motivo per usare C.

In altre parole: la scelta di C è l'unica scelta sana. So che Miles Bader ha scherzosamente detto "per farti incazzare", ma in realtà è vero. Sono giunto alla conclusione che qualsiasi programmatore che preferiscono il progetto di essere in C ++ nel corso C è probabile un programmatore che mi sarei preferisco incazzare, in modo che lui non viene e rovinare qualsiasi progetto sono coinvolto con.

Il C ++ porta a scelte di progettazione davvero pessime. Inevitabilmente inizi a utilizzare le "belle" funzionalità di libreria del linguaggio come STL e Boost e altre cazzate totali e assolute, che possono "aiutare" a programmare, ma causano:

  • quantità infinita di dolore quando non funzionano (e chiunque mi dica che STL e soprattutto Boost sono stabili e portatili è così pieno di BS che non è nemmeno divertente)

  • modelli di programmazione astratti inefficienti in cui due anni dopo notate che alcune astrazioni non erano molto efficienti, ma ora tutto il codice dipende da tutti i bei modelli di oggetti che lo circondano e non è possibile risolverlo senza riscrivere l'app.

In altre parole, l'unico modo per fare C ++ buono, efficiente, a livello di sistema e portatile finisce per limitarti a tutte le cose che sono sostanzialmente disponibili in C. E limitare il tuo progetto a C significa che le persone non lo rovinano e significa anche che hai un sacco di programmatori che in realtà comprendono problemi di basso livello e non rovinano le cose con qualsiasi idiota schifezza da "modello a oggetti".

Quindi mi dispiace, ma per qualcosa come git, in cui l'efficienza era un obiettivo primario, i "vantaggi" del C ++ sono solo un errore enorme. Il fatto che anche noi incazziamo le persone che non riescono a vederlo è solo un grande vantaggio aggiuntivo.

Se vuoi un VCS scritto in C ++, gioca con Monotone. Veramente. Usano un "database reale". Usano "belle librerie orientate agli oggetti". Usano "belle astrazioni C ++". E francamente, come risultato di tutte queste decisioni di progettazione che sembrano così attraenti per alcune persone CS, il risultato finale è un disastro orribile e irraggiungibile.

Ma sono sicuro che ti piacerebbe più di Git.

      Linus

62
Non penso che Linus dovrebbe essere il tipo a cui rivolgersi per discutere qui. I suoi discorsi sono orribilmente soggettivi e immaturi. In realtà ha alcuni punti positivi ma sono così profondamente sepolti (al di sotto delle "cazzate" e delle cazzate) che sono molto difficili da trovare.
Konrad Rudolph,

19
Haha, è stata una bella risata. Non voglio mai incontrare questo ragazzo.
Felix Dombek,

30
Linus mi ricorda un roofer di grande talento che non ha mai appeso il gregge, ma chiama i fan del pensiero dei ragazzi perché usano le viti invece delle unghie.
Bob Murphy,

8
Linus ha ragione, ma lo esprime in modo troppo duro per essere preso sul serio.
Blagovest Buyukliev,

39
Sono d'accordo con @Daniel, se c'è qualcuno che può parlare di superare i limiti dell'hardware è John Carmack, creatore di sventura, terremoto e altri giochi e fondatore del software Id. Scrive questo su c e c ++ su un twitt alcuni mesi fa: "IMO, un buon codice C ++ è meglio di un buon codice C, ma un cattivo C ++ può essere molto, molto peggio di un cattivo codice C." twitter.com/#!/ID_AA_Carmack/status/26560399301
Onema il

18

Non credo che ci siano ragioni valide per usare il C ++. Se si desidera eseguire la programmazione OO, è possibile utilizzare Python invece e scrivere le parti che richiedono prestazioni veloci in C.

EDIT: ci sono altri linguaggi che si interfacciano bene con C, quindi se non ti piace Python, ci sono alternative.


3
Che dire dello sviluppo integrato? Python non è sempre disponibile e la differenza di velocità tra C e C ++ ben scritto è trascurabile sui dispositivi oltre un certo livello di potenza di elaborazione. Ovviamente, suppongo che un compilatore C ++ non sia sempre disponibile ...
James,

6
@James "ben scritto C ++" - c'è il
problema

5
Sono d'accordo con questa risposta, faccio il massimo con Python, dal momento che lo scriverai qualcosa di simile a 3 volte più veloce, profilo, quindi rilascerai colli di bottiglia sostituendoli con C / C ++. È ridondante dire "sostituisci il collo di bottiglia con il codice C ++" poiché non farai alcun livello elevato con il codice che devi essere veloce, poiché sarà un codice di basso livello. C'è una cosa: non so come interfacciare c ++ con python: /. ma in termini di tempo trascorso davanti allo schermo ed efficienza, penso che sia la soluzione migliore, poiché la maggior parte del codice C ++ sarà veloce per niente!
jokoon

8
Vai a lavorare per una grande società finanziaria e costruisci un sistema finanziario complesso in un grande team distribuito in Python e vedi come ti piace. L'esperienza ti insegnerà: a) vantaggi della sicurezza del tipo, b) vantaggi dei compilatori che salvano il tuo sedere, c) codice LUDICROUS che Python consente a nessuno di scrivere. La gente dice che è facile sparare al piede con C ++ -> alcune cose di Python possono funzionare ma essere una follia borderline. In questo momento preferirei di gran lunga lavorare in C ++ ...
MrFox,

1
@suslik: Wow, sono scioccato dal fatto che qualcuno userebbe effettivamente Python per quel tipo di sistema. Sono d'accordo con te sul codice Python Noob difettoso; Ne ho visti anche io.
Larry Coleman,

13

C'è un motivo per usare C ++? Certamente.

Alcune persone potrebbero semplicemente preferire l' uso del C ++ rispetto ad altre opzioni. Chiedere se c'è un motivo per usare il C ++ è come chiedersi perché dobbiamo avere centinaia di gusti di gelato. Non a tutti piace semplicemente attenersi alla Vaniglia.

Se gli sviluppatori sono già molto competenti con il C ++, la domanda per loro potrebbe non essere "perché usarlo?", Ma piuttosto "perché no?". Sembra che ci sia questa cosa alla moda anti-C ++ in corso in SO in questo momento, ma che ci crediate o no, non tutti lo sottoscrivono. Ad alcune persone potrebbe semplicemente piacere C ++ meglio di altre lingue.

Il C ++ deve essere utilizzato per le app? Ovviamente no. Ma questa stessa domanda esatta può essere fatta anche per qualsiasi altra lingua. Esistono pochissimi casi in cui una particolare lingua deve essere utilizzata per un'applicazione.


12

Sto passando da C a C ++ e penso che il guadagno sia considerevole, anche se non hai bisogno di template e OOP.

  • Migliore gestione della memoria
  • Sistema di tipo più forte
  • Una libreria standard migliore
  • Namespace
  • eccetera.

8

Sono sorpreso che nessuno lo abbia ancora menzionato, ma C ++ ci ha fatto conoscere i riferimenti , che quasi risolvono tutti i problemi e le insidie ​​dei puntatori:

void ModifyVar(int& var)
{
    var = 5;
}

int test = 4;
ModifyVar(test);

Invece di:

void ModifyVar(int * var)
{
    *var = 5;
}

int test = 4;
ModifyVar(&test);

Molto più sicuro e anche più facile ... e senza il sovraccarico del passaggio per valore.


3
Anche molto meno flessibile. I riferimenti (in stile C ++) sono efficaci nel semplificare alcuni costrutti comuni in un linguaggio che ha anche dei puntatori, ma non sono affatto sostitutivi dei puntatori, non è nemmeno divertente. E il tuo esempio non è affatto un buon caso per i riferimenti.
Ben Voigt,

3
@Ben: Allora puoi spiegare perché è un cattivo esempio?
Nathan Osman,

6
@ George: Perché non è cambiato nulla, tranne che per due (contali) più brevi? Non risolve alcun problema, non mette in evidenza eventuali insidie, non fa nemmeno nulla di interessante come prolungare la durata di una variabile temporanea (di cui i riferimenti sono validi).
Ben Voigt,

@Ben: stai dimenticando qualcosa: il riferimento è sempre valido. I puntatori possono puntare a qualsiasi cosa (incluso NULL) che può portare a tutti i tipi di errori di memoria se le cose non vengono eseguite correttamente. I riferimenti non possono mai essere NULL e l'indirizzo a cui puntano non può mai essere modificato.
Nathan Osman,

5
@George: "il riferimento è sempre valido" è assolutamente falso. Ti darò un esempio se ne hai bisogno, ma spero che tu sia abbastanza esperto da esserne già consapevole. E non sto nemmeno parlando di formare un riferimento non valido usando un puntatore non valido. Le funzioni che utilizzano i puntatori richiedono una documentazione che indichi le condizioni preliminari sugli argomenti. Ma praticamente parlando, tutte le funzioni hanno bisogno di quel livello di documentazione, quindi è assurdo chiamarlo sciopero contro i puntatori.
Ben Voigt,

5

Il dove e perché di solito saranno:

  • familiarità
  • funzionalità linguistiche desiderate
  • librerie specifiche che si desidera utilizzare
  • requisiti di prestazione

Per la programmazione lato server puoi spesso scegliere tra una miriade di lingue diverse, compilate o interpretate. Di solito la scelta della lingua dipende dalla piattaforma su cui tu o il tuo team sarete più efficaci. O se non hai ancora una squadra, la disponibilità di competenze sul mercato.

In una nota a margine non capisco davvero di decidere di usare C / C ++ in base alle prestazioni (solo) poiché molti linguaggi di scripting sono estendibili con C / C ++. Ottieni il vantaggio di un linguaggio di sviluppo rapido unito alla capacità di migrare le porzioni lente in estensioni C / C ++. Certamente se stai programmando sistemi in cui ogni operazione conta è comprensibile, ma nella maggior parte dello sviluppo di app non capisco.


2
La familiarità è la ragione numero 1 e sono sorpreso che tu sia il primo a parlarne.
Paul Butcher,

4

C ++ vs Python vs Perl non possono essere giudicati facilmente. Dipende dal progetto e dai requisiti.

C ++ ha un arsenale di utility di molto tempo fa, in esecuzione su molte piattaforme. Ma è doloroso iniziare a camminare attraverso i flussi semplicemente passando String a Integer e viceversa.

Il C ++, d'altra parte, ha un pessimo accordo con le dipendenze dalle librerie. Una volta compilato qualcosa in GCC X o VC ++ Y, non puoi fare affidamento sul fatto che il codice verrà eseguito dalla versione successiva di quegli strumenti. Lo stesso inferno è su Windows, lo stesso inferno è anche su Unix.

Perl, prende il potere dal mondo Unix ma soprattutto come strumento di espressione regolare. Questo è ciò che viene utilizzato la maggior parte del tempo. Insieme ad alcuni strumenti piuttosto seri che persino Java non può fare in modo normale (controlla come caricare un file su un server Web), Perl è "fallo".

Python è facile, flessibile e un linguaggio dinamico. Così facile che puoi inviare un numero intero a una funzione, lo script si aspetta una stringa, ma puoi avere un risultato! Inaspettato però, ma un risultato. Quindi il programmatore deve essere molto cauto. IDLE offre un po 'di debug, ma quando TELNET è su un sistema o SSH su tre livelli in basso e vuoi trovare il tuo problema, il debugger non sarà lì per stare accanto a te. Ma può fare un ottimo lavoro di matematica veloce.

Java è un ecosistema di parole d'ordine, tecnologie aliene e grandi parole e quando vuoi semplicemente caricare un file sul server web, scopri che puoi farlo solo se il server ha JSP . Se vuoi chiamare librerie di sistema o funzioni di sistema come il monitoraggio, scopri che devi scavare molto. E forse per raggiungere JNI e OK ... pensi poi ... "Perché, Signore?"

A parte questo, Java è un ottimo strumento per le suite business e il multithreading mi è piaciuto molto.

Velocemente per fare un programma e mostrare al tuo CV "Oh, lo so anche quella tecnologia" e il tuo aspirante capo, lasciati stupire! Anche se, la tecnologia potrebbe non essere quella necessaria ... (OK, gente, odio il Spring Framework ....)


1
ahimè, devi considerare che Python ha dipendenze di versione - specialmente una volta che esegui la migrazione a Python 3, lo stesso con perl .. o qualcuno si è ancora preso la briga di passare a Perl 6? Tutto ha brutte dipendenze :(
gbjbaanb,

3

La cosa da tenere a mente durante la scelta di una lingua, è quale beneficio otterrai dall'usarla e quanto tempo ci vorrà per ottenerla.

L'idea principale tra linguaggi come Python e Perl è fare di più con meno tempo di lavoro, ma con più tempo di CPU. In effetti passerai più tempo a programmare uno script Python o Perl di quanto verrà eseguito, ma ottieni il mio punto.

Il vantaggio di C / C ++ è che sono veloci, ma a un costo di sintassi e digitazione forte: devi fare molto da te in modo che il computer non debba sceglierlo al momento della compilazione.

Quando crei un codice, alcune righe verranno eseguite molto più di altre e quelle righe sono quelle che rappresentano un problema. D'altra parte, tutto il resto del codice, quello su cui hai trascorso molto tempo, viene eseguito molto meno spesso. Potresti averlo sentito, ma è la famigerata regola 80/20 e non sarai in grado di bypassare tale regola.

La soluzione a questo problema è quella di utilizzare un linguaggio più semplice (più semplice intendo più amichevole per gli sviluppatori: meno digitazione, interpretazione pigra, molte routine e cose preesistenti, ecc.) Per fare tutto il codice.

Lo farai così rapidamente rispetto a se lo avessi fatto con C o C ++, ci sarebbe voluto molto più dolore al cervello.

Il tuo programma sarà lento, ma con un profiler, isolerai la parte eseguita l'80% delle volte e li eseguirai con C o C ++.

Pregando in questo modo, hai risparmiato molto tempo e il tuo programma è tanto efficiente, tanto veloce, ha molte meno possibilità di perdere memoria e hai risparmiato tempo.

I linguaggi di scripting sono stati progettati per essere dalla parte dello sviluppatore, ma l'ottimizzazione è ancora possibile. Ovviamente puoi essere un mago del modello di design o un voodoo STL o anche un guerriero lisp, e forse un monaco haskell. Ma le lingue ci fanno parlare con i computer, le lingue non sono fatte per noi BE computer!



2

Il C ++ che uso si chiama C con le classi!


8
Evviva, hai usato la parola chiave 'class'. Ora capisci il design OO!
dss539,

Il mio C ++ si chiama C con spazi dei nomi.
jsz,

6
Il mio C ++ si chiama, umm .. C ++ di Manoj.
Manoj R

+1 lo classifica l'unico motivo per cui utilizzo C ++.
mbq,

... ok, anche le eccezioni.
mbq,

0

In realtà c'è una sola risposta a tutte le domande formate in questo modo. Il miglior motivo per usare la tecnologia X anziché la tecnologia Y (dove X e Y sono approssimativamente allo stesso livello [come quasi tutti i linguaggi di programmazione contemporanei sono]) è perché conosci già X e non conosci Y.

(ma dopo l'arrivo di Haskell, non c'era motivo di usare nient'altro)


0

No, per niente. Se non hai bisogno delle prestazioni e c'è una libreria che puoi usare l'altra lingua, non preoccuparti di C / C ++. Lo faccio solo al giorno d'oggi quando prendo di mira sistemi embedded che non possono (facilmente?) Eseguire lingue. A volte uso C perché sto scrivendo un plugin ma davvero no.

Tuttavia, non userei Python, Perl, ecc. Per evitare di usare C. La mia preferenza è in realtà C #, perché mi piace una buona libreria (che è un punto di forza di .NET) e mi piacciono i linguaggi tipizzati staticamente. Boo è una buona alternativa. Ma davvero Haskell , OCaml , D , ML e simili vanno bene.


7
Hai perso il punto.
Matt Joiner,

@Matt Joiner: sono sicuro di no. Cosa mi sono perso?

La domanda riguarda il non utilizzo di C ++.
Matt Joiner,

@Matt Joiner: hmm, in un'altra occhiata posso vedere che mi viene chiesto. Ma sembra che io abbia risposto anche a questo (ho detto di non preoccuparti e delle alternative che uso)

Voglio quasi sottovalutare questo a causa di C # ...
Vreality
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.