Pertanyaan Mengapa "menggunakan namespace std" dianggap praktik buruk?


Saya telah diberitahu oleh orang lain bahwa menulis using namespace std dalam kode salah, dan yang harus saya gunakan std::cout dan std::cin secara langsung.

Kenapa using namespace std dianggap sebagai praktik yang buruk? Apakah tidak efisien atau apakah berisiko mendeklarasikan variabel ambigu (variabel yang berbagi nama yang sama dengan fungsi di std namespace)? Apakah itu memengaruhi kinerja?


2061
2017-09-21 03:08


asal


Jawaban:


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

using namespace foo;
using namespace bar;

Semuanya berfungsi dengan baik, Anda bisa menelepon Blah() dari Foo dan Quux() dari Bar tanpa masalah. Tetapi suatu hari Anda meng-upgrade ke versi baru Foo 2.0, yang sekarang menawarkan fungsi yang disebut Quux(). Sekarang Anda punya konflik: Impor Foo 2.0 dan Bar Quux() ke ruang nama global Anda. Ini akan membutuhkan upaya untuk memperbaikinya, terutama jika parameter fungsi terjadi untuk cocok.

Jika Anda pernah menggunakannya foo::Blah() dan bar::Quux(), kemudian pengenalan foo::Quux() akan menjadi non-event.


1746
2017-09-21 03:13



Saya setuju dengan semuanya Greg menulis, tapi saya ingin menambahkan: Bahkan bisa lebih buruk daripada kata Greg!

Library Foo 2.0 bisa memperkenalkan fungsi, Quux(), itu adalah kecocokan yang jauh lebih baik untuk beberapa panggilan Anda Quux() daripada bar::Quux() kode Anda disebut selama bertahun-tahun. Maka Anda kode masih dikompilasi, tapi itu diam-diam memanggil fungsi yang salah dan apakah dewa-tahu-apa. Itu sama buruknya dengan hal-hal yang bisa terjadi.

Perlu diingat bahwa std namespace memiliki banyak pengenal, banyak di antaranya sangat yang umum (pikirkan list, sort, string, iterator, dll.) yang sangat mungkin muncul di kode lain juga.

Jika Anda menganggap ini tidak mungkin: Ada sebuah pertanyaan yang ditanyakan di sini di Stack Overflow di mana cukup banyak persis ini terjadi (fungsi salah disebut karena dihilangkan std:: awalan) sekitar setengah tahun setelah saya memberi jawaban ini. Sini adalah contoh lain yang lebih baru dari pertanyaan semacam itu. Jadi ini adalah masalah nyata.


Berikut ini satu lagi poin data: Banyak, bertahun-tahun yang lalu, saya juga terbiasa menemukan itu menjengkelkan harus awalan semuanya dari perpustakaan standar dengan std::. Kemudian saya bekerja di sebuah proyek di mana diputuskan di awal bahwa keduanya using arahan dan deklarasi dilarang kecuali untuk lingkup fungsi. Tebak apa? Dibutuhkan sebagian besar dari kita beberapa minggu untuk terbiasa menulis awalan, dan setelah beberapa minggu, sebagian besar dari kita bahkan setuju bahwa itu benar-benar membuat kode lebih mudah dibaca. Ada alasan untuk itu: Apakah Anda suka prosa lebih pendek atau lebih lama adalah subjektif, tetapi awalan secara obyektif menambah kejelasan kode. Tidak hanya kompilator, tetapi Anda juga merasa lebih mudah untuk melihat pengidentifikasi mana yang dirujuk.

Dalam satu dekade, proyek itu tumbuh memiliki beberapa juta baris kode. Karena diskusi ini muncul lagi dan lagi, saya pernah penasaran seberapa sering (fungsi) lingkup fungsi (dibolehkan) usingsebenarnya digunakan dalam proyek ini. Saya memberikan sumbernya dan hanya menemukan satu atau dua lusin tempat di mana itu digunakan. Bagi saya ini menunjukkan bahwa, sekali dicoba, pengembang tidak menemukan std:: cukup menyakitkan untuk menggunakan arahan bahkan sekali setiap 100 kLoC bahkan ketika itu diizinkan untuk digunakan.


Intinya: Secara eksplisit awalan segala sesuatu tidak membahayakan, sangat sedikit membiasakan diri, dan memiliki keuntungan obyektif. Secara khusus, itu membuat kode lebih mudah ditafsirkan oleh kompiler dan oleh pembaca manusia - dan itu mungkin harus menjadi tujuan utama ketika menulis kode.


1147
2017-09-21 09:26



Saya pikir itu buruk untuk meletakkannya di file header kelas Anda: karena kemudian Anda akan memaksa siapa saja yang ingin menggunakan kelas Anda (dengan menyertakan file header Anda) untuk juga menjadi 'menggunakan' (yaitu melihat semuanya di) ruang nama lain .

Namun, Anda mungkin merasa bebas untuk menempatkan pernyataan menggunakan dalam file * .cpp (pribadi) Anda.


Berhati-hatilah bahwa beberapa orang tidak setuju dengan ucapan saya "merasa bebas" seperti ini - karena meskipun pernyataan menggunakan dalam file cpp adalah lebih baik daripada di header (karena tidak mempengaruhi orang yang menyertakan file header Anda), mereka pikir itu masih belum baik (karena tergantung pada kode itu bisa membuat pelaksanaan kelas lebih sulit dipertahankan). Topik FAQ ini berkata,

Petunjuk penggunaan ada untuk kode C ++ lawas dan untuk memudahkan transisi ke ruang nama, tetapi Anda mungkin tidak boleh menggunakannya secara rutin, setidaknya tidak dalam kode C ++ baru Anda.

Ini menunjukkan dua alternatif:

  • A menggunakan deklarasi:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Dapatkan lebih dari itu dan cukup ketik std ::

    std::cout << "Values:";
    

308
2017-09-21 03:22



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

using namespace std;
using namespace boost;

Banyak Dorongan fitur akan masuk ke standar C ++ 0x, dan Visual Studio 2010 memiliki banyak fitur C ++ 0x, jadi tiba-tiba program ini tidak dikompilasi.

Karena itu, hindari using namespace X; adalah bentuk pemeriksaan masa depan, cara memastikan perubahan ke pustaka dan / atau file header yang digunakan tidak akan merusak program.


197
2017-10-28 17:37



Versi singkat: jangan gunakan global menggunakan deklarasi atau arahan dalam file header. Jangan ragu untuk menggunakannya dalam file implementasi. Inilah yang dikatakan Herb Sutter dan Andrei Alexandrescu tentang masalah ini C ++ Coding Standards (Bolding untuk penekanan adalah milikku):

Ringkasan

Namespace usings adalah untuk kenyamanan Anda, bukan untuk Anda berikan kepada orang lain: Jangan pernah menulis deklarasi menggunakan atau menggunakan direktif sebelum direktif #include.

Corollary: Dalam file header, jangan menulis level namespace menggunakan arahan atau menggunakan deklarasi; sebaliknya, secara eksplisit namespace-memenuhi syarat semua nama. (Aturan kedua mengikuti dari yang pertama, karena header tidak pernah bisa tahu apa yang ada pada header lain #includes mungkin muncul setelahnya.)

Diskusi

Singkatnya: Anda dapat dan harus menggunakan namespace menggunakan deklarasi dan arahan secara bebas dalam file implementasi Anda setelah #include direktif dan merasa baik tentang itu. Meskipun pernyataan berulang untuk sebaliknya, namespace menggunakan deklarasi dan arahan tidak jahat dan mereka tidak mengalahkan tujuan ruang nama. Sebaliknya, mereka adalah apa yang membuat namespace dapat digunakan.


159
2017-11-03 20:00



Orang seharusnya tidak menggunakan direktif di lingkup global, terutama di header. Namun ada situasi yang sesuai bahkan dalam 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 dari kualifikasi eksplisit (std::sin, std::cos...) karena lebih pendek dan memiliki kemampuan untuk bekerja dengan tipe floating point yang ditentukan pengguna (melalui Argument Dependent Lookup).


103
2017-09-21 15:47



Jangan gunakan secara global

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

  • Anda mengacaukan namespace yang Anda program.
  • Pembaca akan kesulitan melihat dari mana asal pengenal tertentu, ketika Anda menggunakan banyak using namespace xyz.
  • Apa pun yang benar untuk lain pembaca kode sumber Anda bahkan lebih benar bagi pembaca yang paling sering: Anda sendiri. Kembalilah dalam satu atau dua tahun dan lihatlah ...
  • Jika Anda hanya berbicara tentang using namespace std Anda mungkin tidak menyadari semua hal yang Anda ambil - dan ketika Anda menambahkan yang lain #include atau pindah ke C ++ revisi baru Anda mungkin mendapatkan konflik nama yang tidak Anda sadari.

Anda dapat menggunakannya secara lokal

Lanjutkan dan gunakan secara lokal (hampir) dengan bebas. Ini, tentu saja, mencegah Anda dari pengulangan std:: - dan pengulangan juga buruk.

Idiom untuk menggunakannya secara lokal

Dalam C ++ 03 ada idiom - kode boilerplate - untuk mengimplementasikan swap berfungsi untuk kelas Anda. Disarankan bahwa Anda benar-benar menggunakan lokal using namespace std -- atau setidaknya using std::swap:

class Thing {
    int    value_;
    Child  child_;
public:
    // ...
    friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
    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&,Child&)` or `std::swap(...)`
}

Ini melakukan sihir berikut:

  • Compiler akan memilih std::swap untuk value_, i.e. void std::swap(int, int).
  • Jika Anda memiliki kelebihan beban void swap(Child&, Child&) mengimplementasikan kompilator akan memilihnya.
  • Jika kamu melakukan tidak memiliki kelebihan yang akan menggunakan compiler void std::swap(Child&,Child&) dan mencoba yang terbaik menukar ini.

Dengan C ++ 11 tidak ada alasan untuk menggunakan pola ini lagi. Implementasi dari std::swap diubah untuk menemukan kelebihan potensial dan memilihnya.


80
2018-01-18 09:34