Domanda

Una caratteristica di C ++ è la possibilità di creare spazi dei nomi senza nome (anonimi), in questo modo:

namespace {
    int cannotAccessOutsideThisFile() { ... }
} // namespace

Penseresti che una tale funzione sarebbe inutile - dal momento che non puoi specificare il nome dello spazio dei nomi, è impossibile accedere a qualcosa al suo interno dall'esterno. Ma questi spazi dei nomi senza nome sono accessibili all'interno del file in cui sono stati creati, come se avessi loro una clausola di utilizzo implicita.

La mia domanda è: perché o quando sarebbe preferibile utilizzare le funzioni statiche? O sono essenzialmente due modi per fare esattamente la stessa cosa?

È stato utile?

Soluzione

Lo standard C ++ si legge nella sezione 7.3.1.1 Spazi dei nomi senza nome, paragrafo 2:

  

L'uso della parola chiave statica è   deprecato quando si dichiarano oggetti in a   ambito dello spazio dei nomi, lo spazio dei nomi senza nome   fornisce un'alternativa superiore.   

Statico si applica solo ai nomi di oggetti, funzioni e unioni anonime, non al tipo di dichiarazioni.

Modifica

La decisione di deprecare questo uso della parola chiave statica (influisce sulla visibilità di una dichiarazione variabile in un'unità di traduzione) è stata annullata ( ref ). In questo caso l'uso di uno spazio dei nomi statico o senza nome è tornato ad essere essenzialmente due modi di fare esattamente la stessa cosa. Per ulteriori discussioni, consulta questa domanda SO

Gli spazi dei nomi senza nome hanno ancora il vantaggio di consentire la definizione di tipi di unità di traduzione locali. Vedi questa domanda SO per maggiori dettagli.

Il merito va a Mike Percy per averlo portato alla mia attenzione.

Altri suggerimenti

L'inserimento di metodi in uno spazio dei nomi anonimo ti impedisce di violare accidentalmente la Una regola di definizione , consentendoti per non preoccuparti mai di nominare i tuoi metodi di supporto allo stesso modo di qualche altro metodo a cui potresti collegarti.

E, come sottolineato da Luke, gli spazi dei nomi anonimi sono preferiti dallo standard rispetto ai membri statici.

C'è un caso limite in cui l'elettricità statica ha un effetto sorprendente (almeno per me). Lo standard C ++ 03 afferma in 14.6.4.2/1:

  

Per una chiamata di funzione che dipende da un parametro modello, se il nome della funzione è un ID non qualificato ma non un ID modello , le funzioni candidate si trovano usando le solite regole di ricerca (3.4.1, 3.4.2) tranne che:

     
      
  • Per la parte della ricerca che utilizza la ricerca del nome non qualificata (3.4.1), vengono trovate solo dichiarazioni di funzioni con collegamento esterno dal contesto di definizione del modello.
  •   
  • Per la parte della ricerca che utilizza gli spazi dei nomi associati (3.4.2), vengono trovate solo le dichiarazioni di funzione con collegamento esterno trovate nel contesto di definizione del modello o nel contesto di istanza del modello.
  •   
     

...

Il codice seguente chiamerà foo (void *) e non foo (S const & amp;) come ci si potrebbe aspettare.

template <typename T>
int b1 (T const & t)
{
  foo(t);
}

namespace NS
{
  namespace
  {
    struct S
    {
    public:
      operator void * () const;
    };

    void foo (void*);
    static void foo (S const &);   // Not considered 14.6.4.2(b1)
  }

}

void b2()
{
  NS::S s;
  b1 (s);
}

Di per sé questo non è probabilmente un grosso problema, ma evidenzia che per un compilatore C ++ pienamente conforme (ovvero uno con supporto per export ) la parola chiave static avrà ancora funzionalità che non è disponibile in nessun altro modo.

// bar.h
export template <typename T>
int b1 (T const & t);

// bar.cc
#include "bar.h"
template <typename T>
int b1 (T const & t)
{
  foo(t);
}

// foo.cc
#include "bar.h"
namespace NS
{
  namespace
  {
    struct S
    {
    };

    void foo (S const & s);  // Will be found by different TU 'bar.cc'
  }
}

void b2()
{
  NS::S s;
  b1 (s);
}

L'unico modo per garantire che la funzione nel nostro spazio dei nomi senza nome non venga trovata nei modelli che utilizzano ADL è renderlo statico .

Aggiornamento per C ++ moderno

A partire da C ++ '11, i membri di uno spazio dei nomi senza nome hanno implicitamente il collegamento interno (3.5 / 4):

  

Uno spazio dei nomi senza nome o uno spazio dei nomi dichiarato direttamente o indirettamente all'interno di uno spazio dei nomi senza nome ha un collegamento interno.

Ma allo stesso tempo, il 14.6.4.2/1 è stato aggiornato per rimuovere la menzione del collegamento (presa da C ++ '14):

  

Per una chiamata di funzione in cui l'espressione postfix è un nome dipendente, le funzioni candidate si trovano usando   le solite regole di ricerca (3.4.1, 3.4.2) tranne che:

     
      
  • Per la parte della ricerca che utilizza la ricerca del nome non qualificata (3.4.1), vengono trovate solo le dichiarazioni di funzione dal contesto di definizione del modello.

  •   
  • Per la parte della ricerca che utilizza gli spazi dei nomi associati (3.4.2), vengono trovate solo le dichiarazioni di funzione trovate nel contesto di definizione del modello o nel contesto di istanza del modello.

  •   

Il risultato è che questa particolare differenza tra membri dello spazio dei nomi statici e senza nome non esiste più.

Di recente ho iniziato a sostituire parole chiave statiche con spazi dei nomi anonimi nel mio codice, ma ho subito riscontrato un problema in cui le variabili nello spazio dei nomi non erano più disponibili per l'ispezione nel mio debugger. Stavo usando VC60, quindi non so se si tratta di un problema con altri debugger. La mia soluzione era quella di definire uno spazio dei nomi 'modulo', dove gli ho dato il nome del mio file cpp.

Ad esempio, nel mio file XmlUtil.cpp, definisco uno spazio dei nomi XmlUtil_I {...} per tutte le variabili e le funzioni del mio modulo. In questo modo posso applicare la qualifica XmlUtil_I :: nel debugger per accedere alle variabili. In questo caso, "_I" lo distingue da uno spazio dei nomi pubblico come XmlUtil che potrei voler usare altrove.

Suppongo che un potenziale svantaggio di questo approccio rispetto a un approccio veramente anonimo sia che qualcuno potrebbe violare l'ambito statico desiderato usando il qualificatore dello spazio dei nomi in altri moduli. Non so se questa sia una delle maggiori preoccupazioni.

L'uso della parola chiave statica a tale scopo è deprecato dallo standard C ++ 98. Il problema con static è che non si applica alla definizione del tipo. È anche una parola chiave sovraccarica utilizzata in diversi modi in contesti diversi, quindi spazi dei nomi senza nome semplificano un po 'le cose.

Per esperienza, noterò solo che mentre è il modo C ++ di inserire funzioni precedentemente statiche nello spazio dei nomi anonimo, i compilatori più vecchi a volte possono avere problemi con questo. Attualmente lavoro con alcuni compilatori per le nostre piattaforme di destinazione e il compilatore Linux più moderno sta bene inserendo le funzioni nello spazio dei nomi anonimo.

Ma un vecchio compilatore in esecuzione su Solaris, a cui siamo tenuti fino a una versione futura non specificata, a volte lo accetterà e altre volte lo contrassegnerà come un errore. L'errore non è ciò che mi preoccupa, è ciò che potrebbe fare quando lo accetta . Quindi fino a quando non diventiamo moderni su tutta la linea, stiamo ancora usando funzioni statiche (di solito nell'ambito della classe) in cui preferiremmo lo spazio dei nomi anonimo.

Inoltre, se si utilizza una parola chiave statica su una variabile come questo esempio:

namespace {
   static int flag;
}

Non sarebbe visibile nel file di mappatura

Avendo appreso di questa funzione solo ora mentre leggo la tua domanda, posso solo speculare. Ciò sembra offrire diversi vantaggi rispetto a una variabile statica a livello di file:

  • Gli spazi dei nomi anonimi possono essere nidificati l'uno nell'altro, fornendo più livelli di protezione da cui i simboli non possono sfuggire.
  • È possibile posizionare più spazi dei nomi anonimi nello stesso file di origine, creando in effetti diversi ambiti a livello statico all'interno dello stesso file.

Sarei interessato a sapere se qualcuno ha usato spazi dei nomi anonimi in codice reale.

Una differenza specifica del compilatore tra spazi dei nomi anonimi e funzioni statiche può essere vista compilando il seguente codice.

#include <iostream>

namespace
{
    void unreferenced()
    {
        std::cout << "Unreferenced";
    }

    void referenced()
    {
        std::cout << "Referenced";
    }
}

static void static_unreferenced()
{
    std::cout << "Unreferenced";
}

static void static_referenced()
{
    std::cout << "Referenced";
}

int main()
{
    referenced();
    static_referenced();
    return 0;
}

Compilare questo codice con VS 2017 (specificando il flag di avviso di livello 4 / W4 per abilitare avviso C4505: la funzione locale non referenziata è stata rimossa ) e gcc 4.9 con la funzione -Wunused-function o -Wall mostra che VS 2017 produrrà solo un avviso per la funzione statica non utilizzata. gcc 4.9 e versioni successive, così come clang 3.3 e versioni successive, genereranno avvisi per la funzione non referenziata nello spazio dei nomi e anche un avviso per la funzione statica non utilizzata.

Demo live di gcc 4.9 e MSVC 2017

Personalmente preferisco le funzioni statiche rispetto agli spazi dei nomi senza nome per i seguenti motivi:

  • dalla definizione della funzione è ovvio e chiaro che è privato per l'unità di traduzione in cui è compilato. Con lo spazio dei nomi senza nome potrebbe essere necessario scorrere e cercare per vedere se una funzione si trova in uno spazio dei nomi.

  • Le funzioni
  • negli spazi dei nomi potrebbero essere trattate come esterne da alcuni compilatori (più vecchi). In VS2017 sono ancora esterni. Per questo motivo, anche se una funzione si trova nello spazio dei nomi senza nome, è comunque possibile contrassegnarli come statici.

  • Le funzioni statiche
  • si comportano in modo molto simile in C o C ++, mentre gli spazi dei nomi senza nome sono ovviamente solo C ++. Anche gli spazi dei nomi senza nome aggiungono ulteriore livello se rientro e non mi piace :)

Quindi, sono felice di vedere quell'uso di static per le funzioni non è più deprecato .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top