Usare `using` in C ++ o evitarlo?


17

Sconti semantici leggermente diversi a causa dell'ADL, come dovrei generalmente usare using e perché? Dipende dalla situazione (es. Intestazione che sarà #included vs. file sorgente che non lo farà)?

Inoltre, dovrei preferire ::std::ostd:: ?

  1. Livello di spazio dei nomi using namespace:

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  2. Essere pienamente espliciti:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
  3. Dichiarazioni di utilizzo a livello di spazio dei nomi:

    using std::pair;
    using std::string;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  4. Dichiarazioni di utilizzo locali delle funzioni:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using std::make_pair;
        return make_pair(s.begin(), s.end());
    }
  5. Funzione locale using namespace:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using namespace std;
        return make_pair(s.begin(), s.end());
    }
  6. Qualcos'altro?

Ciò presuppone pre-C ++ 14 e quindi nessuna deduzione del tipo di ritorno utilizzando auto.



@AProgrammer: Ah, grazie per il link, che risponde a una parte della mia domanda. :) Mi chiedo ancora ::std::contro vs. std::però.
user541686

4
Sto usando stdsenza secondi però. Qualcuno che definisce uno spazio dei nomi standard richiede problemi (e probabilmente cerca di trarre vantaggio dal fatto che la maggior parte delle persone stia usando stde non ::std).
AProgrammer

Risposte:


25

Evitare di utilizzare usingnelle intestazioni, perché ciò interrompe lo scopo degli spazi dei nomi.

Va bene usarlo nei file sorgente, ma lo eviterei comunque in alcuni casi (ad esempio using std).

Tuttavia, se hai spazi dei nomi nidificati, va bene:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A

6
+1 è sorprendente il numero di tutorial e corsi universitari che ti dicono di usare la usingparola chiave senza una spiegazione approfondita del perché gli spazi dei nomi sono usati per cominciare.
Jeffrey Sweeney,

Le persone vogliono andare avanti usando iostreams, stringhe e così via. Non vogliono digitare std :: ogni volta che vogliono usare una cosa, o devono ricordare ancora un altro pezzo di boilerplate da mettere prima del loro codice, che causerà errori tutt'altro che utili se lo dimenticano . :(
Colen,

Qualcosa come typedef std :: string sstring; essere un'alternativa?
Giorgio,

1
@Colen: queste povere anime possono usare using std::coute amici, ma non coutè che sia già un nome orribilmente lungo.
Benjamin Bannier,

1
Se sei uno studente universitario nel tuo primo giorno della "mia prima classe C ++", è ancora un'altra cosa che può causare errori di sintassi che non capisci. È facile per noi capire perché siamo programmatori esperti, ma quando stai cercando di imparare la lingua, è ancora un'altra cosa di cui preoccuparti che non ti serve.
Colen,

11

Quando si inserisce un'istruzione using in un file di origine, PER FAVORE, basta inserire le cose necessarie. Per esempio:

using std::string;
using std::ostringstream;

Il problema qui è che se lo fai

using namespace std;

si inserisce OGNI SINGOLA COSA da std nello spazio dei nomi globale. Il che porta a messaggi di errore molto interessanti quando si utilizza accidentalmente un nome nel codice che corrisponde a uno di cui non si era completamente a conoscenza in std. Se inserisci semplicemente le cose che vuoi, non avrai quel problema (o, più precisamente, il prossimo programmatore che lavorerà sul tuo codice non avrà quel problema).


In alternativa, è possibile using namespacesolo nell'ambito di una funzione, evitando il problema.
Tamás Szelei,

2
@fish - in realtà, facendo 'usando lo spazio dei nomi' nell'ambito della funzione non si evita il problema, si limita a limitare lo spazio in cui le cose possono andare storte. E se finisci per mettere "usando lo spazio dei nomi" in ogni funzione, non è molto diverso dal farlo a livello globale.
Michael Kohne,

Mentre C ++ in effetti consente di dichiarare i tipi a livello di funzione, non è una cosa comune; a parte questo, i possibili conflitti di nomi sono facili da individuare dall'output del compilatore (ma hai ragione, questo non li impedisce).
Tamás Szelei,

2

Come indica VJovic, non utilizzare usingin un file di intestazione. usingin un file di intestazione influisce sull'unità di compilazione corrente (il file .cpp) in modi che il file di origine potrebbe non aspettarsi.

using namespacedeve anche essere evitato in un file sorgente. Questo porta ogni simbolo nello stesso ambito del file sorgente. È più chiaro ai tuoi lettori cosa stai facendo se usi simboli specifici dallo spazio dei nomi.


2
A livello pratico, a meno che il codice non sovrascriva i nomi comunemente usati, preferirei vedere using namespace JoystickModuleall'inizio di un file .cpp piuttosto che JoystickModule::allegato a tutti gli oggetti.
Alex P

@AlexP: Questo è esattamente come lo faccio. Una usingdichiarazione per il mio spazio dei nomi Attualmente sto lavorando e tutto rimane altro namespace.
Benjamin Kloster,

Dovrei approfondire "usare simboli specifici dallo spazio dei nomi". Piuttosto che prefissare ogni simbolo su ogni uso, il che non aiuta con la leggibilità, preferisco usare il sollevamento esplicito di simboli. using SomeNameSpace::SomeSymbol. Ciò evita di spostare tutti i simboli dallo spazio dei nomi all'ambito corrente.
Bill Door

0

Scrivere usingin Headers è il modo migliore per creare tutti i tipi di bug cattivi e impossibili da eseguire il debug . Do Non fare questo.

Scrivere using namespace XYZnel file sorgente è un po 'meglio, ma può comunque causare innumerevoli mal di testa. Il modo sicuro è specificare esplicitamente ciò che si sta utilizzando ad es using Foo::Bar.

Supponiamo che tu abbia Bar.cpp con il seguente:

//Bar.cpp
using namespace Foo;
namespace
{
    double increment(double v) { return (v + 1); }
}

void Bar::someFunction()
{
    //...
    int currentIndex = 0;
    int nextIndex = increment(currentIndex);
    //...
}

La funzione ha funzionato bene, fino a quando un giorno - apparentemente senza alcuna modifica del codice nelle classi pertinenti - il suo comportamento è cambiato: improvvisamente currentIndexsembra sempre essere spento da uno . Scorrendo le modifiche recenti non si rilevano modifiche anche in remoto relative al codice.

Alla fine scopri la causa:
includi (indirettamente) da Foo.hqualche parte. Nei file per lo spazio dei nomi Foo è stata aggiunta una nuova funzione:

//Foo.h
namespace Foo
{
    //...
    int& increment(int& v) { v += 1; return v; };
    //...
}

Che è una corrispondenza inequivocabilmente migliore increment(int)della tua funzione increment(double), quindi ora Foo::increment()viene chiamata la funzione Bar::someFunction(). Ops.

(E se dovessi scrivere usingin Headers che using namespace Foopotrebbe benissimo essere ovunque nel tuo albero include ...)

Quindi ... Non scrivere alcuno usingnelle intestazioni e diffidare di scrivere using namespacenei file sorgente.

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.