2009-05-22 6 views
8

Sono un programmatore C++ e di recente mi sono unito a una nuova società che utilizza molto C. Quando hanno esaminato il mio codice, pensavano che avessi sovrascritto alcune delle cose che non ero affatto d'accordo. La società sta facendo tutto nel sistema embedded, quindi il mio codice deve essere efficiente nella memoria , ma le cose che sto facendo non sono ad alta intensità di CPU. Mi piacerebbe sapere come voi ragazzi pensate quale sia il mio design. Ecco la lista.
Quando ho creato le mie classi di helper, ho finito la progettazione?

  1. devo alcuni array che devono passare intorno e alla fine hanno bisogno di passare a qualche codice C. Potevo passare un puntatore e una dimensione dappertutto. Ma ho scelto di creare una classe che rappresenti questo - una classe che ha un buffer di dimensione fissa (sappiamo la dimensione massima) e una lunghezza che dovrebbe essere sempre < = la dimensione del buffer, altrimenti asserire. In questo modo, posso passare l'array in giro con una sola variabile anziché due, e se la dimensione massima cambia in futuro, dovrei essere in grado di cambiarla facilmente. Non utilizzo l'allocazione dinamica per l'array perché è un sistema incorporato e l'allocazione della memoria potrebbe potenzialmente fallire e non usiamo eccezioni. La classe è probabilmente con meno di 30 righe di codice e io la uso per un bel po 'di posti. Hanno detto che l'ho sovrascritto.

  2. Hanno implementato i propri contenitori in C. Avevo bisogno di usarne uno, ma volevo nascondere tutto il codice dettagliato lontano dalla mia logica principale, così ho creato una classe wrapper per questo. La classe wrapper è simile a stl, quindi ho iteratori e gestisce internamente l'allocazione della memoria , ma a differenza di stl, restituisce un codice di errore quando non può allocare più memoria . Il loro argomento su questo è che io sono l'unico ad usarlo, quindi non vogliono che sia nel repository. Ho trovato stupido ad essere onesto.

EDIT: La classe seguente è più o meno quello che ho usato per il punto 1. Tutto quello che volevo fare è avere qualcosa da passare intorno senza portare la durata per tutto il tempo.

class A 
{ 
    static const MAX_SIZE = 20; 
    int m_Array[MAX_SIZE]; 
    size_t m_Len; 

public: 
    A(const int* array, size_t len) 
    { 
    assert(len <= MAX_SIZE); 
    memcpy(m_Array, array, len); 
    m_Len = len; 
    } 

    size_t GetLen() const { return m_Len; } 
    const int* GetArray() const { return m_Array; } 
}; 

risposta

7

Probabilmente hai ragione, ma d'altra parte, se tutti in azienda ha deciso che don' Mi piacciono le API esistenti e ognuno ha progettato i propri shim e funzioni di supporto, che solo loro utilizzavano, quindi la manutenzione sarebbe difficile.

Se il wrapper di matrice è "sovrascritto", mi chiederei se il revisore del codice consideri qualsiasi quantità di design accettabile. Mi sembra innocuo [*]. Suppongo che potresti aver appena creato una struttura con due membri pubblici, e perdere il beneficio della lettura. Quanto sono cari i tuoi colleghi sulla correttezza generale in generale?

Penso che l'obiettivo per 2 dovrebbe essere quello di raggiungere un consenso sul fatto che l'API C debba essere utilizzata direttamente da C++ o essere spostata. Se deve essere spostato (e gli argomenti per questo sono probabilmente abbastanza forti, cosa con namespacing e RAII), progettare un wrapper che tutti useranno e designarlo "l'API C++ per questo modulo" piuttosto che "un wrapper C++ quello modulo utilizza per questo altro modulo ".

È possibile che tutti gli altri preferiscano l'API così com'è, più un'API OO o l'utilizzo di STL. Seguendo le loro convenzioni sarà più facile per loro mantenere il proprio codice, purché le loro convenzioni siano un solido stile di programmazione in C. Il C++ è un linguaggio multi-paradigma e "C con un numero limitato di campane e fischi" non è il paradigma a cui sei abituato. Ma è un paradigma valido, e se è quello che usa la base di codice esistente, allora devi chiedersi se ciò di cui la tua azienda ha bisogno in questo momento è una rivoluzione da un solo uomo, comunque illuminata.

[*] (l'API, che è. Potrebbero chiedersi se sarà passato per valore in modo inappropriato, e se è saggio per ogni istanza di dover essere grande come il più grande. Questo è tutto per voi a discutere fuori con il revisore, ma non ha nulla a che fare con "over-design"

1

Non sono sicuro di 1. Forse potresti fornire un semplice esempio di codice per illustrare.

Per quanto riguarda 2, sono d'accordo con te. Essendo un programmatore C indurito che sta cercando di aggiornarsi su C++, sono totalmente venduto dall'idea di scrivere facciate sottili attorno alle API C esistenti, per facilità di gestione degli errori e gestione delle risorse.

+0

Ho inserito un codice di esempio nella modifica. – leiz

2

Da un lato, se sei a tuo agio con C++ e usano C, allora le classi di supporto sono probabilmente una buona cosa, almeno per te. D'altra parte, se stai scrivendo qualsiasi tipo di classe contenitore, è quasi certamente meglio usare STL direttamente e scrivere una funzione di supporto per colmare il divario tra il tuo contenitore STL e il codice C. Non reinventare la ruota.

+0

Non stavo cercando di reinventare la ruota e questo è esattamente il motivo per cui ho creato una classe wrapper invece di creare un nuovo contenitore. – leiz

8

Per prima cosa: sei entrato in una nuova azienda, quindi puoi aspettarti di imparare a giocare secondo le loro regole. Sei ancora "il nuovo tipo" e ci sarà una certa resistenza al "tuo modo" di fare le cose, anche se è meglio. Abituati a loro e integri lentamente te stesso e le tue idee.

Per quanto riguarda il numero 1, passare un puntatore + dimensione è sicuramente un problema per il programmatore, ma è il modo più efficiente di memoria per fare le cose. La tua classe non è "finita", ma cosa succede se MAXSIZE diventa davvero grande ad un certo punto nel futuro? Tutte le tue istanze occuperanno molto spazio, anche quando non ne hanno bisogno. Potresti finire a corto di spazio semplicemente perché MAXSIZE è cambiato, anche se non c'era bisogno di molto spazio.

Per quanto riguarda il n. 2, si tratta di un livello non necessario (forse sarebbe più adatto per migliorare il proprio wrapper invece di semplicemente ricomporlo di nuovo?), Ma questo si ridurrà a quanto bene si integri con loro e dare suggerimenti.

In sintesi, non mi chiamo "overdesigned", ma in una situazione incorporata è necessario essere molto prudenti di generalizzare il codice per risparmiare fatica vs memoria risparmio ..

+6

+1 su ingraziarsi con la nuova squadra. Dagli tempo, dimostrati, quindi inizia a catalizzare il cambiamento. Impegnarsi in lotte di potere subito non ti aiuterà a lungo termine. – Cheeso

2

"Over progettato" è molto parente. I C-guys del tuo gruppo probabilmente vedono un problema con la tua classe, perché quando passi la classe per riferimento, creerai una copia dell'intero array. Ciò può richiedere una buona quantità di tempo su un sistema "incorporato" (a seconda della tua definizione di embedded) Naturalmente, se passi per indirizzo, questo non è un problema.

Il numero 2 è un problema culturale. Se non sono disposti a provare nuove tecniche di programmazione, allora sarai visto come un estraneo. È qualcosa che non vuoi che accada. Presentali lentamente.

Per non inserirlo nel repository - è una cazzata. Tutti dovrebbero mettere tutto nel repository in modo che le persone possano accedervi e trovare bug in seguito.

Non a toot il mio proprio corno, ma ho fatto una domanda relativa a pochi giorni fa: Using C++ in an embedded environment

1

Si effettua una copia dei dati per la classe, che non qualifica più la classe come una semplice classe wrapper. i dati vengono cancellati da sotto di te, se i dati originali sono stati modificati, i tuoi dati non saranno aggiornati

L'idea di incapsulare la matrice con la dimensione è ragionevole.Forse puoi convincerli ad acquistare aggiungendo il campo dimensione al loro contenitore, assumendo che non sia solo un const int *. Ma posso vedere che per il semplice privilegio di incapsulare la dimensione, il sovraccarico di memoria extra e runtime per modellare e inizializzare la classe può sembrare sgradevole per loro.

Oltre a ciò, devo capire fino in fondo il classico C-bias, ovvero C++ è lento e malvagio. Flashback ... brivido.

3

Un wrapper C++ per la libreria di contenitori in stile c già esistente è una buona cosa da avere. Ma assicurati che sia davvero un involucro, non un involucro con campane e fischietti imbullonati.

Se dichiarate tutte le funzioni di accesso come inline e scrivete il vostro wrapper utilizzando l'implementazione più snella possibile, ci dovrebbe essere esattamente zero overhead nel codice e nella dimensione dei dati.

Tale wrapper fornirà un'interfaccia simile alla classe alla libreria c, ed è una buona pratica per un progetto C/C++.

Suggerisco di controllare il codice. Dai un'occhiata allo smontaggio di un piccolo test-case usando il tuo wrapper e confrontalo con un'implementazione c-only. Se vedi complessità, allocazioni o chiamate aggiuntive alla tua implementazione di classe, hai un sovraccarico e forse un po 'di overengineering.

Provare che il proprio wrapper genera codice più o meno identico rispetto alla versione c può convincere gli altri programmatori che un involucro qua e là non fa male. Segue il modo in cui i programmi C++ vengono scritti e si tradurrà in un codice più pulito e più coerente.

Btw - La "cosa non vogliamo inutile classe wrapper nel nostro repository" è un problema sociale, non tecnico. Sei il nuovo ragazzo. Se fossi nella tua posizione, giocherei secondo le loro regole per un paio di mesi e - dopo che mi sarò dimostrato - presenterò le tue idee.

Problemi correlati