Kodėl „std vardų naudojimas“ laikomas bloga praktika?

Man buvo pasakyta, kad kodo rašymo kodas using namespace std yra neteisingas, o vietoj to turėčiau naudoti std::cout ir std::cin .

Kodėl using namespace std laikoma bloga praktika? Ar tai neveiksminga, ar ji gali paskelbti dviprasmiškus kintamuosius (kintamuosius, kurie turi tą patį pavadinimą kaip funkcija std )? Ar tai veikia našumą?

2212
21 сент. nustatė akbiggs rugsėjo 21 d 2009-09-21 06:08 '09, 06:08 am. 2009-09-21 06:08
@ 36 atsakymai
  • 1
  • 2

Tai nėra susijusi su našumu. Tačiau apsvarstykite tai: jūs naudojate dvi bibliotekas, vadinamas „Foo“ ir „Bar“:

 using namespace foo; using namespace bar; 

Viskas veikia gerai, galite skambinti Blah() iš Foo ir Quux() iš Bar be jokių problemų. Bet vieną dieną Quux() prie naujos „Foo 2.0“ versijos, kuri dabar siūlo funkciją „ Quux() . Dabar jūs turite konfliktą: tiek „Foo 2.0“, tiek „Bar“ importuoja Quux() savo pasaulinėje vardų erdvėje. Tam reikės tam tikrų pastangų, kad būtų išspręstos, ypač jei funkcijos parametrai yra vienodi.

Jei naudojote foo::Blah() ir bar::Quux() , tada foo::Quux() įvedimas būtų ne įvykis.

1863 m
21 сент. atsakymas, kurį pateikė Greg Hewgill rugsėjo 21 d 2009-09-21 06:13 '09 6:13 2009-09-21 06:13

Sutinku su tuo, ką rašė Gregas , bet norėčiau pridurti: jis netgi gali pablogėti, nei sakė Greg!

Foo 2.0 biblioteka gali pristatyti Quux() funkciją, kuri tikrai atitinka kai kuriuos jūsų Quux() skambučius nei bar::Quux() , kurio kodas buvo pakviestas daugelį metų. Tada jūsų kodas vis dar surenkamas , bet jis tyliai vadina neteisingą funkciją ir Dievas žino, ką. Tai yra maždaug taip blogai, kaip viskas gali būti.

Turėkite omenyje, kad std yra daug identifikatorių, kurių daugelis yra labai dažni (mąstymo list , sort , string , iterator ir kt.), iterator greičiausiai pasirodo ir kitu kodu.

Jei manote, kad tai mažai tikėtina: buvo klausimas, kuriame aprašoma, kaip tai įvyko (neteisinga funkcija, kurią sukėlė std:: prefix trūkumas). maždaug pusę metų po to, kai daviau šį atsakymą. Čia yra dar vienas naujausias tokio klausimo pavyzdys. Taigi tai yra tikra problema.


Čia yra dar vienas duomenų taškas: prieš daugelį metų aš taip pat prisiėmiau prielaidą, kad tai erzina prielaidą visiems iš standartinės std:: bibliotekos. Tada dirbau projekte, kuriame pradžioje buvo nuspręsta, kad direktyvų ir deklaracijų naudojimas yra draudžiamas, išskyrus funkcijų sritis. Atspėkite, ką? Daugelis iš mūsų turėjo labai mažai savaičių, kad galėtume įprasti rašyti priešdėlį, o po kelių savaičių daugelis iš mūsų net sutiko, kad kodas tikrai tapo aiškesnis. Tai yra priežastis: Jei jums patinka trumpesnis arba ilgesnis proza, tai yra subjektyvus, bet priešdėliai objektyviai prideda kodo aiškumą. Ne tik kompiliatorius, bet ir jums lengviau matyti, kuris identifikatorius yra paminėtas.

Per dešimt metų šis projektas išaugo iki kelių milijonų kodų eilučių. Kadangi šios diskusijos kyla vėl ir vėl, buvau įdomu, kaip dažnai projekte using naudojamas (leistinas) funkcijų plotas. Radau šio šaltinio ir rado tik vieną ar dvi dešimtis vietų, kuriose jis buvo naudojamas. Man tai rodo, kad, kai bandoma, kūrėjai nepakankamai std:: skausmingi, kad galėtų naudoti direktyvas net vieną kartą per 100 kLo, net jei leidžiama naudoti.


Apatinė eilutė: Aiškiai įvardijama, kad viskas nekenkia, labai mažai naudojama ir turi objektyvių pranašumų. Visų pirma, jis supaprastina kompiliatoriaus ir žmogaus skaitytojų kodo aiškinimą - ir tai turbūt turėtų būti pagrindinis tikslas, kai rašomas kodas.

1214
21 сент. atsakymas pateikiamas sbi 21 Sep 2009-09-21 12:26 '09, 12:26 2009-09-21 12:26

Problema, susijusi su using namespace naudojimu jūsų klasių antraštėse, yra ta, kad tai verčia visus, kurie nori naudotis savo klasėmis (įskaitant antraštės failus), taip pat „naudoti“ (tai yra, pamatyti viską) šių kitų vardų vietų.

Tačiau galite naudoti naudodamiesi pareiškimą savo (privačiame) * .cpp failuose.


Atminkite, kad kai kurie žmonės nesutinka su tokiu teiginiu: „nors laisvas„ cpp “pareiškimas yra geresnis nei antraštė (nes tai neturi įtakos žmonėms, kurie įtraukia antraštės failą), jie galvoja kad tai vis dar nėra gera (nes, priklausomai nuo kodo, tai gali apsunkinti klasės įgyvendinimą). Ši dažnai užduodama tema pasakoja

Naudojama direktyva egzistuoja pasenusiam C + + kodui ir palengvina perėjimą prie vardų erdvių, tačiau tikriausiai neturėtumėte ją naudoti reguliariai, bent jau naujuoju C + + kodu.

DUK siūlo dvi alternatyvas:

  • Naudojimo deklaracija:

     using std::cout; // a using-declaration lets you use cout without qualification cout << "Values:"; 
  • Tiesiog įveskite std ::

     std::cout << "Values:"; 
337
21 сент. atsakymas, kurį pateikė ChrisW rugsėjo 21 d 2009-09-21 06:22 '09 6:22 am 2009-09-21 06:22

Neseniai susidūriau su skundu dėl „ Visual Studio 2010“ . Paaiškėjo, kad beveik visi šaltinio failai turi dvi eilutes:

 using namespace std; using namespace boost; 

Daugelis „ Boost“ funkcijų yra įtrauktos į „C ++ 0x“ standartą, o „Visual Studio 2010“ turi daug C + 0x, todėl šios programos nebuvo sukompiliuotos.

Todėl vengiant using namespace X; Tai yra būsimos patikros forma, užtikrinanti, kad naudojamų bibliotekų pakeitimai ir (arba) antraštės failai netrukdytų programai.

213
28 окт. Atsakyti David Thornley 28 sp 2010-10-28 20:37 '10, 20:37, 2010-10-28 20:37

Trumpoji versija: nenaudokite visuotinio deklaracijų ar direktyvų naudojimo antraštės rinkmenose. Nesivaržykite juos naudoti savo įgyvendinimo failuose. Čia, ką Herb Sutter ir Andrei Aleksandrescu turi pasakyti apie šį klausimą „ C ++“ kodavimo standartuose (paryškinti mano dėmesiui):

Santrauka

Vardų erdvės pavadinimai yra skirti jūsų patogumui, o ne kitiems: niekada nerašykite naudojimo deklaracijos ar naudojimo direktyvos prieš #include direktyvą.

Pasekmė: nenurodykite vardų lygio antraštės rinkmenose, naudodami direktyvas ar deklaracijas; vietoj to vardų sritis yra aiški - atitinka visus vardus. (Antroji taisyklė išplaukia iš pirmojo, nes antraštės niekada negali žinoti, kad po jų gali atsirasti kita #.

Pokalbis

Trumpai tariant, jūs galite ir turėtumėte naudoti vardų sritį su deklaracijomis ir direktyvomis savo įgyvendinimo failuose po #include ir jaustis gerai. Nepaisant pakartotinių teiginių priešingai, vardų erdvė, kurioje naudojamos deklaracijos ir direktyvos, nėra bloga, ir jie nesiekia vardų erdvės tikslo. Greičiau tai leidžia jums naudoti vardų vietas .

178
03 нояб. atsakymas, kurį pateikė mattnewport 03 nov . 2014-11-03 23:00 '14 23:00 val. 2014-11-03 23:00

Jūs negalite naudoti direktyvos pasauliniu mastu, ypač antraštėse. Tačiau yra atvejų, kai tai net taikoma antraštės faile:

 template <typename FloatType> inline FloatType compute_something(FloatType x) { using namespace std; //no problem since scope is limited return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4)); } 

Tai geriau nei aiški kvalifikacija ( std::sin , std::cos ...), nes ji yra trumpesnė ir turi galimybę dirbti su vartotojo nustatytais kintamojo taško tipais (per argumentų priklausomą paiešką).

110
21 сент. atsakymas pateikiamas robson3.14 21 sep . 2009-09-21 18:47 '09, 18:47, 2009-09-21 18:47

Nenaudokite jo visame pasaulyje.

Jis laikomas „blogu“ tik tada, kai jis naudojamas visame pasaulyje . Nes:

  • Jūs užteršiate vardų erdvę, kurioje esate programavimas.
  • Skaitytojams bus sunku matyti, kur gaunamas konkretus identifikatorius, kai naudojate daug using namespace xyz .
  • Nepriklausomai nuo kitų šaltinio kodų skaitytojų, tai dar labiau pasakytina apie dažniausiai skaitytoją: save. Sugrįžkite po metų ar dviejų ir žiūrėkite ...
  • Jei kalbate tik apie using namespace std , gali būti, kad nežinote apie visas surinktas medžiagas, o kai pridėsite kitą #include arba perkelsite į naują „C ++“ versiją, galite gauti vardų konfliktus, apie kuriuos nežinojote.

Galite jį naudoti vietoje.

Eikite į priekį ir naudokite ją vietoje (beveik) laisvai. Tai, žinoma, neleidžia pasikartoti std:: - ir pakartojimas taip pat yra blogas.

Idiomas vietiniam naudojimui

C ++ 03 buvo idiomas - šablono kodas, skirtas klasių swap funkcijai įgyvendinti. Buvo pasiūlyta, kad jūs iš tikrųjų naudojate vietinį using namespace std - arba bent jau using std::swap :

 class Thing { int value_; Child child_; public: // ... friend void swap(Thing  Thing  }; void swap(Thing  Thing  { using namespace std; // make `std::swap` available // swap all members swap(a.value_, b.value_); // `std::stwap(int, int)` swap(a.child_, b.child_); // `swap(Child or `std::swap(...)` } 

Ji veikia taip:

  • Kompiliatorius pasirinks std::swap value_ , t.y. void std::swap(int, int) .
  • Jei turite void swap(Child Child> perkrovą, kompiliatorius jį pasirinks.
  • Jei neturite šios perkrovos, kompiliatorius naudos void std::swap(Child> ir pabandys juos pakeisti geriausiai.

C ++ 11 nebėra priežasties naudoti šį šabloną. std::swap įgyvendinimas buvo pakeistas, kad rastų galimą perkrovą ir jį pasirinktumėte.

86
18 янв. Atsakymą pateikė towi Jan 18 2013-01-18 12:34 '13, 12:34 2013-01-18 12:34

Jei importuojate teisingus antraštės failus, staiga pavardės, pvz., hex , left , plus arba count pasauliniu mastu. Tai gali būti stebina, jei nežinote, kad std:: yra šie pavadinimai. Jei taip pat bandote naudoti šiuos vardus vietoje, tai gali sukelti painiavą.

Jei visi standartiniai elementai yra savo vardų erdvėje, nereikia nerimauti dėl pavadinimo prieštaravimo jūsų kodui ar kitoms bibliotekoms.

73
21 сент. atsakymas pateikiamas sth 21 sep. 2009-09-21 06:23 '09 6:23 am 2009-09-21 06:23

Patyrę programuotojai naudoja viską, kas išsprendžia jų problemas, ir vengia naujų problemų, ir jie vengia naudoti rodyklės direktyvas ant šios tikslios priežasties.

Patyrę programuotojai taip pat stengiasi, kad pavadinimai nevisiškai atitiktų jų šaltinio failus. Nedidelė priežastis yra tai, kad nėra elegantiško parašyti daugiau kodų, jei kodų nėra, jei nėra įtikinamų priežasčių. Pagrindinė priežastis yra ta, kad paieškos priklausomas argumentas (ADL) yra išjungtas.

Kokios yra šios geros priežastys? Kartais programuotojai akivaizdžiai nori išjungti ADL, kitais atvejais jie nori pašalinti dviprasmiškumą.

Taigi, viskas tvarkinga:

  • Direktyvų naudojimas funkcijų lygmeniu ir deklaracijų naudojimas vykdant funkcijas
  • Naudokite šaltinio lygio deklaracijas šaltinio failuose
  • (Kartais) naudojant šaltinio failo lygį
39
29 марта '11 в 11:10 2011-03-29 11:10 atsakymą pateikė Aleksandras Poluektovas, kovo 29 d. 11 val. 11:10 2011-03-29 11:10

Kita priežastis yra netikėtumas.

Jei aš pamatysiu „ cout << blah o ne std::cout << blah

Manau, kas tai yra cout ? Ar tai yra normalu? Ar tai kažkas ypatingo?

37
21 сент. Atsakymas, kurį pateikė Martin Beckett 21 Sep 2009-09-21 06:13 '09 6:13 2009-09-21 06:13

Sutinku, kad jis negali būti naudojamas visame pasaulyje, bet ne toks blogas, kad jį būtų galima naudoti vietoje, kaip ir namespace . Štai „C ++ programavimo kalbos“ pavyzdys:

 namespace My_lib { using namespace His_lib; // everything from His_lib using namespace Her_lib; // everything from Her_lib using His_lib::String; // resolve potential clash in favor of His_lib using Her_lib::Vector; // resolve potential clash in favor of Her_lib } 

Šiame pavyzdyje mes išsprendėme galimus vardų susidūrimus ir neaiškumus, susijusius su jų sudėtimi.

Vardai, kurie yra aiškiai deklaruoti (įskaitant vardus, deklaruotus naudojant tokias deklaracijas kaip His_lib::String ), yra svarbesni už vardus, kurie yra prieinami kitoje srityje, naudojant naudojimo direktyvą ( using namespace Her_lib ).

36
29 авг. Atsakymas pateikiamas Oleksiy 29 rug. 2013-08-29 12:44 '13, 12:44, 2013-08-29 12:44

Taip pat manau, kad tai bloga praktika. Kodėl? Tik tada, kai maniau, kad vardų erdvės funkcija yra padalinti medžiagą taip, kad nenorėčiau jo sugadinti viskas į vieną pasaulinį maišelį. Tačiau, jei dažnai naudoju „cout“ ir „cin“, rašau: using std::cout; using std::cin; using std::cout; using std::cin; cpp faile (niekada antraštės faile, nes jis platinamas naudojant #include ). Manau, kad niekas nesėkmingai niekada neskambins srautų ar cin .)

26
21 сент. atsakymas duotas „ Yelonek 21“ sep . 2009-09-21 12:34 '09, 12:34 2009-09-21 12:34

Malonu matyti kodą ir žinoti, ką jis daro. Jei matau std::cout , žinau, kad std bibliotekos srautas. Jei matau cout , tada aš nežinau. Tai gali būti cout bibliotekos srautas. Arba galbūt tik int cout = 0; tose pačiose funkcijose yra daugiau nei dešimt eilučių. Arba static kintamasis, pavadintas „ cout “ šiame faile. Tai gali būti bet kas.

Dabar pasiimkite milijoną eilutės kodo, kuris nėra itin didelis, ir ieškote klaidos, o tai reiškia, kad žinote, kad šioje eilutėje yra viena eilutė, kuri nedaro to, kas turėtų būti padaryta. cout << 1; gali skaityti static int pavadinimą „ cout , perkelti jį paliekant vieną bitą ir išmesti rezultatą. Ieškodamas klaidos, turiu tai patikrinti. Ar matote, kaip aš tikrai norėčiau pamatyti std::cout ?

Tai vienas iš tų dalykų, kurie atrodo kaip tikrai gera idėja, jei esate mokytojas ir niekada neturėjote rašyti ir išlaikyti jokio gyvenimo kodo. Man patinka pamatyti kodą, kur (1) žinau, ką jis daro; ir (2) Esu tikras, kad tai rašantis asmuo žinojo, ką jis daro.

21
13 марта '14 в 20:22 2014-03-13 20:22 atsakymas duotas gnasher729 kovo 13 d. 14 val. 20:22 2014-03-13 20:22

Viskas apie sudėtingumo valdymą. Naudodamiesi vardų erdve atsiras kažkas, ko nenorite, todėl gali būti sunkiau derinti (sakau, galbūt). Naudojant std :: visur sunkiau skaityti (daugiau teksto ir visa tai).

Arkliai kursams - valdykite savo sudėtingumą, kaip galite ir galite jaustis.

20
21 сент. atsakymas duotas Preet Sangha 21 sep . 2009-09-21 06:14 '09 6:14 am. 2009-09-21 06:14

Atrodo, kad daugelio vardų erdvių naudojimas yra nelaimės receptas, tačiau, mano nuomone, naudojant JUST vardų std ir tik std vardų erdvė nėra didelis dalykas, nes perrašymas gali įvykti tik pagal jūsų kodą. .

Taigi tiesiog laikykite juos rezervuotais vardais, tokiais kaip „int“ arba „klasė“, ir tai yra viskas.

Žmonės turėtų nustoti būti tokie analiniai. Jūsų mokytojas visą laiką buvo teisus. Tiesiog naudokite ONE vardų erdvę; tai yra visas taškas, kuriame visų pirma reikia naudoti vardų vietas. Vienu metu neturėtumėte naudoti daugiau nei vieną. Jei tai ne tavo. Taigi naujo apibrėžimo nebus.

17
09 нояб. atsakymas, kurį pateikė vartotojo2645752 09 lapkritis 2013-11-09 18:09 '13, 18:09 2013-11-09 18:09
  • Turite sugebėti skaityti žmonių, kurie turi skirtingas nuomones apie stilių ir geriausią praktiką, parašytą kodą.

  • Jei naudojate „cout“, niekas nesijaučia. Bet kai turite daug vardų, kurie skrenda, ir jūs matote šią klasę, ir jūs nesate visiškai tikri, ką jis daro, nes aiški vardų erdvė veikia kaip komentaras. Iš pirmo žvilgsnio galite pamatyti: „Oi, tai yra failų sistemos veikimas“ arba „Kas daro tinklo daiktus“.

17
21 сент. atsakymą pateikė Dustin Getz 21 sep. 2009-09-21 07:04 '09, 07:04 2009-09-21 07:04

Bus svarstoma

 // myHeader.h #include <sstream> using namespace std; // someoneElses.cpp/h #include "myHeader.h" class stringstream { // uh oh }; 

Atkreipkite dėmesį, kad tai paprastas pavyzdys, jei turite failų su 20 įtrauktų ir kitų importuojamų prekių, jums bus daug priklausomybių, kad išspręstumėte problemą. Labiausiai blogai, galite gauti nesusijusias klaidas kituose moduliuose, priklausomai nuo konfliktų apibrėžimų.

Tai nėra baisi, bet jūs atsikratysite galvos skausmo, nenaudodami jo antraštės rinkmenose arba pasaulinėje vardų erdvėje. Labiausiai tikėtina, kad tai gali būti padaryta labai ribotose srityse, bet aš niekada neturėjau problemų įvedus papildomus 5 simbolius, kad sužinotumėte, iš kur yra mano funkcijos.

16
21 сент. atsakymą pateikė Ron Warholic 21 sep . 2009-09-21 06:19 '09 at 6:19 AM 2009-09-21 06:19

Konkretus problemos paaiškinimo pavyzdys. Įsivaizduokite, kad turite situaciją, kurioje yra 2 bibliotekos: foo ir bar, kiekviena su savo vardų erdve:

 namespace foo { void a(float) {  } } namespace bar { ... } 

Pasakykime, kad naudodami foo ir barą savo programoje naudosite taip:

 using namespace foo; using namespace bar; void main() { a(42); } 

Šiuo metu viskas tvarkinga. Kai vykdote programą, ji „daro kažką“. Tačiau vėliau atnaujinate skydą ir sakote, kad tai pasikeitė:

 namespace bar { void a(float) {  } } 

Šiuo metu gausite kompiliatoriaus klaidą:

 using namespace foo; using namespace bar; void main() { a(42); // error: call to 'a' is ambiguous, should be foo::a(42) } 

Taigi, jums reikės atlikti tam tikrą techninę priežiūrą, kad išsiaiškintumėte, ką reiškia „a“ (t.y., foo::a ). Tai tikriausiai nepageidautina, tačiau, laimei, tai gana paprasta (tiesiog pridėkite foo:: prieš visus skambučius, kuriuos kompiliatorius nurodo kaip dviprasmišką).

Bet įsivaizduokite alternatyvų scenarijų, kuriame juosta vietoj to pasikeitė, kad atrodytų taip:

 namespace bar { void a(int) {  } } 

Šiuo metu jūsų skambutis į a(42) staiga tampa prijungtas prie bar::a o ne foo::a o vietoj to, kad kažką padarytų, tai daro kažką visiškai kitokio. Nėra kompiliatoriaus įspėjimo ar nieko kito. Jūsų programa tik pradeda daryti kažką kitokio, nei anksčiau.

Kai naudojate vardų sritį, kyla panašaus scenarijaus rizika, todėl žmonės gali nepatogiai naudotis vardų erdvėmis. Kuo daugiau dalykų vardų erdvėje, tuo didesnė konfliktų rizika, todėl žmonės gali būti dar nepatogesni naudoti std vardų erdvę (dėl to, kad yra daug dalykų šioje vardų erdvėje) nei kitos vardų vietos.

Galiausiai tai yra kompromisas tarp įrašymo pajėgumų ir patikimumo / priežiūros. Skaitymas taip pat gali būti svarbus, bet aš vis tiek galiu matyti argumentus. Paprastai sakyčiau, kad patikimumas ir prieinamumas yra svarbesni, tačiau šiuo atveju jūs nuolat mokėsite už retą patikimumą ir prieinamumą. „Geriausias“ kompromisas nulems jūsų projektą ir prioritetus.

11
02 сент. Atsakymą pateikė Kevin 02 Sep. 2016-09-02 23:06 '16 at 23:06 pm 2016-09-02 23:06

Vardų erdvė yra pavadinta sritis. Vardų vietos naudojamos susietoms deklaracijoms grupuoti ir atskirai atskirti. Pavyzdžiui, dvi atskirai sukurtos bibliotekos gali naudoti tą patį pavadinimą skirtingiems, tačiau naudotojas gali naudoti abu:

 namespace Mylib{ template<class T> class Stack{  }; / / ... } namespace Yourlib{ class Stack{  }; / / ... } void f(int max) { Mylib: :Stack<int> s1(max) ; / / use my stack Yourlib: :Stack s2(max) ; / / use your stack / / ... } 

Повторение имени пространства имен может быть отвлечением как для читателей, так и для писателей. Следовательно, возможно чтобы указать, что имена из определенного пространства имен доступны без явной квалификации. Pavyzdžiui:

 void f(int max) { using namespace Mylib; / / make names from Mylib accessible Stack<int> s1(max) ; / / use my stack Yourlib: :Stack s2(max) ; / / use your stack / / ... }