c++ - vectors - vector resize




Una dichiarazione può influire sullo spazio dei nomi standard? (2)

Il codice causa un comportamento indefinito.

C ++ 17 [extern.names] / 4:

Ogni firma di funzione dalla libreria standard C dichiarata con collegamento esterno è riservata all'implementazione per l'uso come firma di funzione con collegamento "C" esterno e "C ++" esterno o come nome dell'ambito dello spazio dei nomi nello spazio dei nomi globale.

Quindi non è possibile creare una funzione con lo stesso prototipo della funzione di libreria C standard int abs(int); . Indipendentemente da quali intestazioni includi effettivamente o se tali intestazioni inseriscono anche i nomi delle librerie C nello spazio dei nomi globale.

Tuttavia, sarebbe possibile sovraccaricare gli abs se si forniscono diversi tipi di parametri.

#include <iostream>
#include <cmath>

/* Intentionally incorrect abs() which seems to override std::abs() */
int abs(int a) {
    return a > 0? -a : a;
}

int main() {
    int a = abs(-5);
    int b = std::abs(-5);
    std::cout<< a << std::endl << b << std::endl;
    return 0;
}

Mi aspettavo che l'output fosse -5 e 5 , ma l'output è -5 e -5 .

Mi chiedo perché questo caso accadrà?

Ha qualcosa a che fare con l'uso di std o cosa?


La specifica del linguaggio allows alle implementazioni di implementare <cmath> dichiarando (e definendo) le funzioni standard nello spazio dei nomi globale e poi portandole nello spazio dei nomi std mediante using-dichiarazioni. Non è specificato se si utilizza questo approccio

20.5.1.2 Intestazioni
4 [...] Nella libreria standard C ++, tuttavia, le dichiarazioni (ad eccezione dei nomi definiti come macro in C) rientrano nell'ambito dei namespace (6.3.6) dello spazio dei nomi std . Non è specificato se questi nomi (compresi eventuali sovraccarichi aggiunti nelle clausole da 21 a 33 e nell'Allegato D) siano prima dichiarati nell'ambito globale dello spazio dei nomi e poi iniettati nello spazio dei nomi std mediante dichiarazioni esplicite usando (10.3.3).

Apparentemente, hai a che fare con una delle implementazioni che hanno deciso di seguire questo approccio (ad esempio GCC). Vale a dire la tua implementazione fornisce ::abs , mentre std::abs semplicemente "si riferisce" a ::abs .

Una domanda che rimane in questo caso è perché oltre allo standard ::abs sei stato in grado di dichiarare il tuo ::abs , ovvero perché non ci sono errori di definizione multipla. Ciò potrebbe essere causato da un'altra funzionalità fornita da alcune implementazioni (ad esempio GCC): dichiarano le funzioni standard come i cosiddetti simboli deboli , consentendo così di "sostituirle" con le proprie definizioni.

Questi due fattori insieme creano l'effetto che si osserva: la sostituzione del simbolo debole di ::abs comporta anche la sostituzione di std::abs . Quanto bene questo concorda con lo standard linguistico è una storia diversa ... In ogni caso, non fare affidamento su questo comportamento - non è garantito dalla lingua.

In GCC questo comportamento può essere riprodotto dal seguente esempio minimalista. Un file sorgente

#include <iostream>

void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }

Un altro file sorgente

#include <iostream>

void foo();
namespace N { using ::foo; }

void foo() { std::cout << "Goodbye!" << std::endl; }

int main()
{
  foo();
  N::foo();
}

In questo caso noterai anche che la nuova definizione di ::foo ( "Goodbye!" ) Nel secondo file sorgente influenza anche il comportamento di N::foo . Entrambe le chiamate genereranno "Goodbye!" . E se rimuovi la definizione di ::foo dal secondo file sorgente, entrambe le chiamate invieranno alla definizione "originale" di ::foo e produrranno "Hello!" .

L'autorizzazione data dal 20.5.1.2/4 sopra è lì per semplificare l'implementazione di <cmath> . Le implementazioni possono semplicemente includere lo stile C <math.h> , quindi dichiarare nuovamente le funzioni in std e aggiungere alcune aggiunte e modifiche specifiche per C ++. Se la spiegazione sopra descritta descrive correttamente la meccanica interna del problema, allora gran parte di essa dipende dalla sostituibilità dei simboli deboli per le versioni in stile C delle funzioni.

Se semplicemente sostituiamo globalmente int con double nel programma precedente, il codice (sotto GCC) si comporterà "come previsto" - genererà -5 5 . Ciò accade perché la libreria standard C non ha la funzione abs(double) . Dichiarando i nostri abs(double) , non sostituiamo nulla.

Ma se dopo il passaggio da int con double passiamo anche da abs a fabs , lo strano comportamento originale riapparirà nella sua piena gloria (output -5 -5 ).

Ciò è coerente con la spiegazione sopra.





reserved