Mengapa "std namespace use" dianggap praktik buruk?

Saya diberitahu bahwa menulis kode using namespace std dalam kode salah, dan saya harus menggunakan std::cout dan std::cin sebagai gantinya.

Mengapa using namespace std dianggap praktik buruk? Apakah itu tidak efektif atau dapatkah ia menyatakan variabel ambigu (variabel yang memiliki nama yang sama dengan fungsi di std )? Apakah itu mempengaruhi kinerja?

2212
21 сент. diatur oleh akbiggs 21 Sep 2009-09-21 06:08 '09 pada pukul 6:08 pagi 2009-09-21 06:08
@ 36 jawaban
  • 1
  • 2

Ini tidak terkait dengan kinerja sama sekali. Tetapi pertimbangkan ini: Anda menggunakan dua perpustakaan yang disebut Foo and Bar:

 using namespace foo; using namespace bar; 

Semuanya berfungsi dengan baik, Anda dapat memanggil Blah() dari Foo dan Quux() dari Bar tanpa masalah. Tetapi suatu hari Anda pindah ke versi baru Foo 2.0, yang sekarang menawarkan fitur yang disebut Quux() . Anda sekarang memiliki konflik: Foo 2.0 dan Bar import Quux() di namespace global Anda. Ini akan membutuhkan beberapa upaya untuk memperbaikinya, terutama jika parameter fungsi sama.

Jika Anda menggunakan foo::Blah() dan bar::Quux() , maka pengenalan foo::Quux() akan menjadi non-event.

1863
21 сент. balasan yang diberikan oleh Greg Hewgill 21 Sep 2009-09-21 06:13 '09 pada 6:13 2009-09-21 06:13

Saya setuju dengan semua yang ditulis Greg , tetapi saya ingin menambahkan: Bahkan mungkin lebih buruk dari yang dikatakan Greg!

Pustaka Foo 2.0 dapat memperkenalkan fungsi Quux() , yang pastinya lebih cocok untuk beberapa panggilan Quux() daripada bar::Quux() , yang kodenya telah dipanggil selama bertahun-tahun. Maka kode Anda masih dikompilasi , tetapi diam-diam memanggil fungsi yang salah dan Tuhan tahu apa. Ini sama buruknya dengan semuanya.

Perlu diingat bahwa std berisi banyak pengidentifikasi, banyak di antaranya sangat umum (think list , sort , string , iterator , dll.), Yang kemungkinan besar juga muncul di kode lain.

Jika Anda pikir ini tidak mungkin: ada pertanyaan yang menjelaskan bagaimana hal itu terjadi (fungsi yang salah disebabkan oleh hi>std:: :). sekitar setengah tahun setelah saya memberikan jawaban ini. Ini adalah contoh lain dari pertanyaan semacam itu. Jadi ini masalah sebenarnya.


Berikut ini adalah titik data lain: bertahun-tahun yang lalu, saya juga terbiasa berasumsi bahwa ini mengganggu perlunya awalan untuk semua orang dari std:: library standar. Kemudian saya bekerja di sebuah proyek di mana pada awalnya diputuskan bahwa arahan dan using deklarasi dilarang, dengan pengecualian area fungsi. Coba tebak? Sebagian besar dari kita memiliki beberapa minggu untuk membiasakan diri menulis awalan, dan setelah beberapa minggu, sebagian besar dari kita bahkan setuju bahwa itu benar-benar membuat kode lebih mudah dibaca. Ada alasan untuk ini: Jika Anda suka prosa pendek atau lebih lama, itu subjektif, tetapi awalan secara objektif menambah kejelasan kode. Tidak hanya kompiler, tetapi juga lebih mudah bagi Anda untuk melihat pengenal mana yang disebutkan.

Dalam sepuluh tahun, proyek ini telah berkembang menjadi beberapa juta baris kode. Karena diskusi ini muncul beru>std:: cukup menyakitkan untuk menggunakan arahan bahkan setiap 100 kLoC bahkan di tempat yang diizinkan untuk digunakan.


Intinya: Secara eksplisit awalan semuanya tidak membahayakan, sangat sedikit digunakan dan memiliki keuntungan obyektif. Secara khusus, ini menyederhanakan interpretasi kode oleh kompiler dan pembaca manusia - dan ini mungkin harus menjadi tujuan utama saat menulis kode.

1214
21 сент. jawabannya diberikan sbi 21 Sep 2009-09-21 12:26 '09 pada 12:26 2009-09-21 12:26

Masalah dengan using namespace dalam file header kelas Anda adalah bahwa hal itu memaksa siapa pun yang ingin menggunakan kelas Anda (termasuk file header) untuk juga "menggunakan" (yaitu, lihat semuanya) ruang nama lain ini.

Namun, Anda dapat dengan bebas menggunakan pernyataan penggunaan dalam file * .cpp Anda (pribadi).


Ingat bahwa beberapa orang tidak setuju dengan pernyataan "merasa bebas" saya seperti ini - karena walaupun menggunakan pernyataan cpp lebih baik daripada tajuk (karena itu tidak memengaruhi orang yang memasukkan file tajuk Anda), menurut mereka bahwa ini masih tidak baik (karena, tergantung pada kode, ini dapat mempersulit pelaksanaan kelas). Topik pertanyaan yang sering diajukan ini mengatakan

Arahan penggunaan ada untuk kode C ++ yang usang dan untuk memfasilitasi transisi ke ruang nama, tetapi Anda mungkin tidak boleh menggunakannya secara teratur, setidaknya dalam kode C ++ yang baru.

FAQ menawarkan dua alternatif:

  • Deklarasi penggunaan:

     using std::cout; // a using-declaration lets you use cout without qualification cout << "Values:"; 
  • Cukup ketik std ::

     std::cout << "Values:"; 
337
21 сент. balasan yang diberikan oleh ChrisW 21 Sep 2009-09-21 06:22 '09 pada pukul 6:22 pagi 2009-09-21 06:22

Saya baru-baru ini menghadapi keluhan tentang Visual Studio 2010 . Ternyata hampir semua file sumber memiliki dua baris:

 using namespace std; using namespace boost; 

Banyak fungsi Boost termasuk dalam standar C ++ 0x, dan Visual Studio 2010 memiliki banyak C ++ 0x, sehingga program-program ini tidak dikompilasi.

Oleh karena itu, hindari using namespace X; Ini adalah bentuk pemeriksaan di masa depan, cara untuk memastikan bahwa perubahan dalam perpustakaan yang digunakan dan / atau file header tidak mengganggu program.

213
28 окт. Balas David Thornley 28 Okt 2010-10-28 20:37 '10 pada 20:37 2010-10-28 20:37

Versi singkat: Jangan gunakan penggunaan deklarasi atau arahan global dalam file header. Jangan ragu untuk menggunakannya dalam file implementasi Anda. Di sini, apa yang dikatakan Herb Sutter dan Andrei Aleksandrescu tentang masalah ini dalam C ++ Standar Pengkodean (tebal untuk perhatian saya):

Ringkasan

Nama namespace adalah untuk kenyamanan Anda, bukan untuk orang lain: jangan pernah menuliskan deklarasi penggunaan atau gunakan arahan sebelum arahan #include.

Konsekuensi: jangan mencatat level namespace dalam file header menggunakan arahan atau menggunakan deklarasi; sebaliknya, namespace eksplisit - memenuhi syarat semua nama. (Aturan kedua mengikuti dari yang pertama, karena pos tidak akan pernah tahu bahwa pos #includes yang berbeda mungkin muncul setelah mereka.)

Bicara

Singkatnya: Anda bisa dan harus menggunakan namespace dengan deklarasi dan arahan dalam file implementasi Anda setelah #include dan merasa nyaman. Meskipun beru> Sebaliknya, ini adalah apa yang memungkinkan Anda untuk menggunakan ruang nama .

178
03 нояб. jawaban yang diberikan oleh mattnewport 03 Nov. 2014-11-03 23:00 '14 pukul 23:00 2014-11-03 23:00

Anda tidak dapat menggunakan arahan pada skala global, terutama di pos. Namun, ada situasi di mana ini bahkan berlaku di file header:

 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)); } 

Ini lebih baik daripada kualifikasi eksplisit ( std::sin , std::cos ...) karena lebih pendek dan memiliki kemampuan untuk bekerja dengan tipe floating-point yang ditentukan pengguna (melalui pencarian yang bergantung pada argumen).

110
21 сент. jawabannya diberikan robson3.14 21 sep . 2009-09-21 18:47 '09 pada 18:47 2009-09-21 18:47

Jangan menggunakannya secara global.

Itu dianggap "buruk" hanya jika digunakan secara global . Karena:

  • Anda mengacaukan namespace di mana Anda pemrograman.
  • Pembaca akan mengalami kesulitan melihat dari mana pengenal tertentu berasal ketika Anda menggunakan banyak using namespace xyz .
  • Apa pun yang benar bagi pembaca kode sumber Anda yang lain, ini bahkan lebih benar bagi pembaca yang paling sering: diri Anda sendiri. Kembalilah dalam satu atau dua tahun dan lihat ...
  • Jika Anda hanya berbicara tentang using namespace std , Anda mungkin tidak tahu tentang semua materi yang Anda ambil, dan ketika Anda menambahkan #include atau pindah ke versi baru C ++, Anda mungkin mendapatkan konflik nama yang tidak Anda ketahui.

Anda dapat menggunakannya secara lokal.

Silakan dan gunakan secara lokal (hampir) secara bebas. Ini, tentu saja, mencegah repetisi dari std:: - dan repetisi juga buruk.

Idiom untuk penggunaan lokal

Di C ++ 03, ada idiom - kode templat - untuk mengimplementasikan fungsi swap untuk kelas Anda. Telah disarankan agar Anda benar-benar menggunakan lokal using namespace std - atau setidaknya 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(...)` } 

Ia melakukan keajaiban berikut:

  • Kompiler akan memilih std::swap untuk value_ , mis. void std::swap(int, int) .
  • Jika Anda menerapkan void swap(Child Child> , kompiler akan memilihnya.
  • Jika Anda tidak memiliki kelebihan ini, kompiler akan menggunakan void std::swap(Child> dan mencoba untuk menggantinya.

C ++ 11 bukan alasan untuk menggunakan templat ini lagi. Implementasi std::swap telah dimodifikasi untuk menemukan potensi kelebihan dan pilihnya.

86
18 янв. Jawabannya diberikan oleh towi 18 Jan 2013-01-18 12:34 '13 pada 12:34 2013-01-18 12:34

Jika Anda mengimpor file header yang benar, Anda tiba-tiba memiliki nama seperti hex , left , plus atau count skala global Anda. Ini bisa mengejutkan jika Anda tidak tahu bahwa std:: berisi nama-nama ini. Jika Anda juga mencoba menggunakan nama-nama ini secara lokal, ini dapat menyebabkan beberapa kebingungan.

Jika semua elemen standar ada di ruang namanya sendiri, Anda tidak perlu khawatir tentang konflik nama dengan kode Anda atau pustaka lainnya.

73
21 сент. jawabannya diberikan sth 21 sept. 2009-09-21 06:23 '09 pada 6:23 pagi 2009-09-21 06:23

Pemrogram berpengalaman menggunakan segala sesuatu yang menyelesaikan masalah mereka, dan menghindari masalah baru yang muncul, dan mereka menghindari menggunakan arahan pointer di tingkat header untuk alasan yang tepat ini.

Pemrogram berpengalaman juga mencoba untuk menghindari kualifikasi nama dalam file sumber mereka. Alasan kecil untuk ini adalah bahwa tidak elegan untuk menulis lebih banyak kode jika tidak ada cukup kode, jika tidak ada alasan kuat. Alasan utama untuk ini adalah bahwa argumen dependen pencarian (ADL) dinonaktifkan.

Apa alasan bagus ini? Terkadang programmer jelas ingin menonaktifkan ADL, dalam kasus lain mereka ingin menghi>

Jadi, semuanya teratur:

  • Penggunaan arahan di tingkat fungsi dan penggunaan deklarasi dalam implementasi fungsi
  • Gunakan deklarasi tingkat sumber di file sumber
  • (Kadang-kadang) menggunakan-pada tingkat file sumber
39
29 марта '11 в 11:10 2011-03-29 11:10 jawabannya diberikan oleh Alexander Poluektov pada 29 Maret '11 di 11:10 2011-03-29 11:10

Alasan lain adalah kejutan.

Jika saya melihat cout << blah bukannya std::cout << blah

Saya pikir apa ini cout ? Apakah itu cout normal? Apakah ini sesuatu yang istimewa?

37
21 сент. Balas diberikan oleh Martin Beckett 21 Sep 2009-09-21 06:13 '09 pada 6:13 2009-09-21 06:13

Saya setuju bahwa itu tidak dapat digunakan secara global, tetapi tidak terlalu jahat untuk digunakan secara lokal, seperti di namespace . Berikut adalah contoh dari "Bahasa Pemrograman C ++":

 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 } 

Dalam contoh ini, kami menyelesaikan tabrakan dan ambiguitas nama potensial yang terkait dengan komposisi mereka.

Nama yang secara eksplisit dideklarasikan di sana (termasuk nama yang dideklarasikan menggunakan deklarasi seperti His_lib::String ) didahulukan dari nama yang tersedia di area lain menggunakan direktif using namespace Her_lib ( using namespace Her_lib ).

36
29 авг. Jawabannya diberikan Oleksiy 29 Agustus. 2013-08-29 12:44 '13 pada 12:44 2013-08-29 12:44

Saya juga menganggap ini sebagai praktik buruk. Mengapa Hanya sekali saya berpikir bahwa fungsi namespace adalah untuk membagi materi sehingga saya tidak akan merusaknya dengan membuang semuanya ke dalam satu tas global. Namun, jika saya sering menggunakan "cout" dan "cin", saya menulis: using std::cout; using std::cin; using std::cout; using std::cin; dalam file cpp (tidak pernah dalam file header, karena didistribusikan menggunakan #include ). Saya pikir tidak ada orang waras yang tidak akan pernah memanggil stream cout atau cin .;)

26
21 сент. jawabannya diberikan Yelonek 21 sep . 2009-09-21 12:34 '09 pada 12:34 2009-09-21 12:34

Senang melihat kode dan tahu apa fungsinya. Jika saya melihat std::cout , saya tahu bahwa aliran cout dari perpustakaan std . Jika saya melihat cout , maka saya tidak tahu. Ini bisa menjadi aliran cout dari perpustakaan std . Atau mungkin int cout = 0; sepuluh baris lebih tinggi dalam fungsi yang sama. Atau variabel static bernama cout dalam file ini. Itu bisa apa saja.

Sekarang ambil satu juta baris kode baris yang tidak terlalu besar, dan Anda mencari kesalahan, yang berarti Anda tahu bahwa ada satu baris dalam sejuta baris ini yang tidak melakukan apa yang seharusnya dilakukan. cout << 1; dapat membaca static int bernama cout , geser ke kiri sedikit dan buang hasilnya. Mencari kesalahan, saya harus memeriksanya. Apakah Anda melihat betapa saya lebih suka melihat std::cout ?

Ini adalah salah satu dari hal-hal ini yang sepertinya ide yang sangat bagus jika Anda seorang guru dan tidak pernah harus menulis dan memelihara kode untuk hidup. Saya suka melihat kode di mana (1) Saya tahu apa fungsinya; dan, (2) saya yakin bahwa orang yang menulis ini tahu apa yang dia lakukan.

21
13 марта '14 в 20:22 2014-03-13 20:22 jawabannya diberikan gnasher729 13 Maret '14 pada 20:22 2014-03-13 20:22

Segala sesuatu tentang mengelola kompleksitas. Menggunakan namespace akan mengarah pada sesuatu yang tidak Anda inginkan, dan karena itu mungkin lebih sulit untuk di-debug (saya katakan, mungkin). Menggunakan std :: di mana-mana lebih sulit untuk dibaca (lebih banyak teks dan semua itu).

Kuda untuk kursus - kelola kompleksitas Anda yang Anda bisa dan rasakan.

20
21 сент. jawabannya diberikan Preet Sangha 21 September . 2009-09-21 06:14 '09 pada 6:14 pagi 2009-09-21 06:14

Menggunakan banyak namespace pada saat yang sama tampaknya menjadi resep untuk bencana, tetapi menggunakan JUST namespace std dan hanya namespace std bukan masalah besar, menurut pendapat saya, karena redefinisi hanya dapat terjadi oleh kode Anda sendiri .. .

Jadi anggap saja mereka sebagai nama yang dicadangkan, seperti "int" atau "kelas", dan itu saja.

Orang harus berhenti bersikap anal. Guru Anda benar sepanjang waktu. Cukup gunakan SATU namespace; itulah inti dari menggunakan ruang nama di tempat pertama. Anda tidak boleh menggunakan lebih dari satu per satu. Jika ini bukan milikmu. Jadi redefinisi tidak akan terjadi.

17
09 нояб. jawaban yang diberikan oleh user2645752 09 Nov. 2013-11-09 18:09 '13 pada 18:09 2013-11-09 18:09
  • Anda harus dapat membaca kode yang ditulis oleh orang-orang yang memiliki pendapat berbeda tentang gaya dan praktik terbaik daripada Anda.

  • Jika Anda menggunakan cout, tidak ada yang malu. Tetapi ketika Anda memiliki banyak ruang nama yang terbang, dan Anda melihat kelas ini, dan Anda tidak begitu yakin apa fungsinya, karena namespace eksplisit bertindak sebagai semacam komentar. Anda dapat melihat sekilas: "Oh, ini adalah operasi sistem file" atau "Apa yang membuat barang-barang jaringan."

17
21 сент. jawabannya diberikan oleh Dustin Getz 21 September. 2009-09-21 07:04 '09 pada 7:04 2009-09-21 07:04

Akan mempertimbangkan

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

Harap perhatikan bahwa ini adalah contoh sederhana, jika Anda memiliki 20 file yang disertakan dan impor lainnya, Anda akan memiliki banyak dependensi untuk menyelesaikan masalah. Yang terburuk, Anda bisa mendapatkan kesalahan yang tidak terkait dalam modul lain, tergantung pada definisi yang bertentangan.

Ini tidak buruk, tetapi Anda akan menghi>

16
21 сент. balasan diberikan kepada Ron Warholic 21 September 2009-09-21 06:19 '09 pada pukul 6:19 AM 2009-09-21 06:19

Contoh spesifik untuk mengklarifikasi masalah. Bayangkan Anda memiliki situasi di mana Anda memiliki 2 perpustakaan, foo dan bar, masing-masing dengan ruang nama sendiri:

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

Sekarang katakanlah Anda menggunakan foo dan bar bersama dalam program Anda sendiri sebagai berikut:

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

Pada titik ini, semuanya beres. Ketika Anda menjalankan program Anda, itu "melakukan sesuatu." Tetapi kemudian Anda memperbarui panel dan mengatakan bahwa itu telah berubah seperti ini:

 namespace bar { void a(float) {  } } 

Pada titik ini, Anda akan mendapatkan kesalahan kompiler:

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

Jadi, Anda perlu melakukan pemeliharaan untuk menjelaskan apa arti "a" (mis., foo::a ). Ini mungkin tidak diinginkan, tetapi, untungnya, ini cukup sederhana (tambahkan saja foo:: sebelum semua panggilan yang ditandai oleh kompiler sebagai ambigu).

Tapi bayangkan skenario alternatif di mana bilah sebaliknya berubah menjadi seperti ini:

 namespace bar { void a(int) {  } } 

Pada titik ini, panggilan Anda ke a(42) tiba-tiba menjadi terhubung ke bar::a bukannya foo::a dan alih-alih melakukan sesuatu, itu melakukan sesuatu yang sama sekali berbeda. Tidak ada peringatan kompiler atau yang lainnya. Program Anda baru saja mulai melakukan sesuatu yang sangat berbeda dari sebelumnya.

Saat Anda menggunakan namespace, Anda menghadapi risiko skenario yang sama, sehingga orang tidak nyaman menggunakan ruang nama. Semakin banyak hal di namespace, semakin besar risiko konflik, sehingga orang mungkin lebih nyaman menggunakan std namespace (karena jumlah hal dalam namespace ini) daripada ruang nama lain.

Pada akhirnya, ini adalah pertukaran antara kemampuan perekaman dan keandalan / pemeliharaan. Keterbacaan mungkin juga penting, tetapi saya dapat melihat argumennya. Biasanya, saya akan mengatakan bahwa keandalan dan rawatan lebih penting, tetapi dalam hal ini Anda akan terus membayar biaya pencatatan untuk keandalan / rawatan yang agak jarang. Tradeoff “terbaik” akan menentukan proyek Anda dan prioritas Anda.

11
02 сент. Jawabannya diberikan oleh Kevin 02 Sep. 2016-09-02 23:06 '16 pada 11:06 malam 2016-09-02 23:06

Namespace adalah ruang lingkup bernama. Ruang nama digunakan untuk mengelompokkan deklarasi terkait dan memisahkan item yang terpisah. Например, две отдельно разработанные библиотеки могут использовать одно и то же имя для обозначения разных но пользователь может использовать оба:

 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 / / ... } 

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

 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 / / ... }