Perché il cast di "void *" non è implicitamente inserito in C ++?

27

In C, non c'è bisogno di lanciare un void * su un altro tipo di puntatore, è sempre promosso in modo sicuro. Tuttavia, in C ++, questo non è il caso. Per es.,

int *a = malloc(sizeof(int));

funziona in C, ma non in C ++. (Nota: so che non dovresti usare malloc in C ++, o per quanto riguarda new , e preferirei invece puntatori intelligenti e / o STL, questo è richiesto puramente per curiosità) Perché lo standard C ++ non consentire questo cast implicito, mentre lo standard C lo fa?

    
posta wolfPack88 09.03.2015 - 15:30
fonte

4 risposte

37

Perché le conversioni di tipo implicito di solito non sono sicure e C ++ prende una posizione più sicura per la digitazione rispetto a C.

C di solito consente conversioni implicite, anche se la maggior parte delle probabilità è che la conversione sia un errore. Questo perché C presume che il programmatore sappia esattamente cosa sta facendo, e se no, è il problema del programmatore, non il problema del compilatore.

C ++ di solito non consente le cose che potrebbero potenzialmente essere degli errori e richiede che tu dichiari esplicitamente la tua intenzione con un cast di tipo. Questo perché il C ++ sta cercando di essere programmatore-friendly.

Potresti chiedere come mai è amichevole quando in realtà ti richiede di digitare altro.

Bene, vedi, ogni linea di codice, in qualsiasi programma, in qualsiasi linguaggio di programmazione, verrà generalmente letta molte più volte di quanto non verrà scritto (*). Quindi, la facilità di lettura è molto più importante della facilità di scrittura. E quando si legge, avere qualsiasi conversione potenzialmente pericolosa si distingue per mezzo di cast di tipi espliciti aiuta a capire cosa sta succedendo e ad avere un certo livello di certezza che ciò che sta accadendo è in realtà ciò che era destinato ad accadere.

Inoltre, l'inconveniente di dover digitare il cast esplicito è banale rispetto all'inconveniente di ore e ore di risoluzione dei problemi per trovare un bug che è stato causato da un incarico errato di cui avresti potuto essere avvisato, ma non lo sei mai stato.

(*) Idealmente verrà scritto una sola volta, ma verrà letto ogni volta che qualcuno dovrà esaminarlo per determinarne l'idoneità al riutilizzo e ogni volta che si verificherà la risoluzione dei problemi e ogni volta che qualcuno dovrà aggiungere del codice vicino ad esso, e poi ogni volta che c'è la risoluzione dei problemi del codice vicino, e così via. Questo è vero in tutti i casi tranne che per gli script "write-once, run, then throw away" e quindi non c'è da meravigliarsi che la maggior parte dei linguaggi di scripting abbia una sintassi che facilita la facilità di scrittura con totale disprezzo per facilitare la lettura. Hai mai pensato che perl sia completamente incomprensibile? Non sei solo. Pensa a linguaggi come "lingue di sola scrittura".

    
risposta data 09.03.2015 - 15:35
fonte
26

Ecco cosa dice Stroustrup :

In C, you can implicitly convert a void* to a T*. This is unsafe

Poi continua a mostrare un esempio di come * può essere pericoloso * e dice:

... Consequently, in C++, to get a T* from a void* you need an explicit cast. ...

Infine, nota:

One of the most common uses of this unsafe conversion in C is to assign the result of malloc() to a suitable pointer. For example:

int* p = malloc(sizeof(int));

In C++, use the typesafe new operator:

int* p = new int;

Si approfondisce su questo argomento in La progettazione e l'evoluzione di C ++ .

Quindi la risposta si riduce a: Il progettista del linguaggio ritiene che sia un modello non sicuro, e quindi reso illegale e fornito modi alternativi per realizzare ciò che il modello è stato normalmente utilizzato.

    
risposta data 09.03.2015 - 17:56
fonte
11

In C, there is no need to cast a void * to any other pointer type, it is always safely promoted.

È sempre promosso, sì, ma difficilmente sicuro .

C ++ disabilita questo comportamento proprio perché tenta di avere un sistema di tipi più sicuro di C, e questo comportamento è non sicuro.

Considera in generale questi 3 approcci alla conversione del tipo:

  1. obbliga l'utente a scrivere tutto, quindi tutte le conversioni sono esplicite
  2. presume che l'utente sappia cosa sta facendo e converta qualsiasi tipo in qualsiasi altro
  3. implementare un sistema di tipo completo con generici sicuri per tipo (modelli, nuove espressioni), operatori espliciti di conversione definiti dall'utente e forzare solo le conversioni esplicite di cose che il compilatore non può vedere sono implicitamente sicuri

Bene, 1 è brutto e un ostacolo pratico per ottenere qualcosa, ma potrebbe essere realmente utilizzato dove è necessaria una grande attenzione. C ha approssimativamente optato per 2, che è più facile da implementare, e C ++ per 3, che è più difficile da implementare ma più sicuro.

    
risposta data 09.03.2015 - 15:35
fonte
1

Per definizione, un puntatore vuoto può indicare qualsiasi cosa. Ogni puntatore può essere convertito in un puntatore void e, quindi, sarete in grado di convertire indietro arrivando allo stesso identico valore. Tuttavia, i puntatori ad altri tipi potrebbero avere vincoli, come le restrizioni di allineamento. Ad esempio, immagina un'architettura in cui i caratteri possano occupare qualsiasi indirizzo di memoria, ma i numeri interi devono iniziare anche sui limiti dell'indirizzo. In alcune architetture, i puntatori interi potrebbero anche contare 16, 32 o 64 bit alla volta in modo che un char * possa effettivamente avere un multiplo del valore numerico di int * mentre punta allo stesso posto in memoria. In questo caso, la conversione da un void * arrotonderebbe effettivamente i bit che non possono essere recuperati e quindi non è reversibile.

In parole povere, il puntatore del vuoto può puntare a qualsiasi cosa, comprese cose a cui altri puntatori potrebbero non essere in grado di puntare. Pertanto, la conversione al puntatore del vuoto è sicura ma non il contrario.

    
risposta data 09.03.2015 - 16:01
fonte

Leggi altre domande sui tag