Apa itu polusi "menggunakan namespace"?


15

Saya sedang melihat panduan pengkodean google [di sini] dan mereka tidak merekomendasikan yang menggunakan using namespaceatau namespace::function- jika saya tidak salah mengartikannya.

Apakah ini berlaku stdjuga? cout<<tidak bekerja tanpanya. Buku ini , merekomendasikan hal yang sama. Jadi bagaimana cara menggunakan cout<<tanpa using namespace std;atau std::cout<<?

Apa cara yang disarankan? std::cout<<? Sebagian besar buku teks c ++ mengajarkan pemula dengan using namespace std;mereka menyebarkan praktik pengkodean yang buruk?

Jawaban:


18

Ketika saya membaca standar Google, Anda tidak dapat menggunakan using namespace foo;arahan di mana pun. Arahan ini membawa semua yang dinyatakan dalam namespace dan merupakan penyebab umum tabrakan dan perilaku tak terduga. Orang lain telah mengutip yang sangat umum: Anda memiliki metode max atau min Anda sendiri di suatu tempat dan bertabrakan dalam file src di mana seseorang menyertakan header dengan metode Anda dan kemudian berkatausing namespace std;

Di tempat-tempat tertentu, diizinkan untuk menggunakan deklarasi penggunaan, yang merupakan bentuk using ::foo::bar;

Orang-orang suka menggunakan arahan dalam kode mereka karena menghemat banyak pengetikan, tetapi berisiko. Jika Anda memiliki file dengan banyak pernyataan cout, saya bisa mengerti tidak ingin harus mengetik std :: cout seratus kali, tetapi Anda bisa mengatakan menggunakan :: std :: cout. Saya memperlakukan deklarasi variabel seperti ini: lingkup di mana mereka dibutuhkan. Jika satu fungsi dalam file 10 perlu menulis output, jangan mendeklarasikan cara cout di atas, taruh di fungsi yang melakukan output aktual.

#include <ostream>
//using namespace std; // NO!
//using ::std::cout;   // less bad than using namespace, but I prefer to scope it

int main(int argc, char** argv)
{
   int rc = do_some_stuff(argc, argv);
   using ::std::endl;
   if (rc) { // print the success report
      using ::std::cout;
      cout << "The test run completed. The return code was " << rc << '.' << endl;
    } else {
      using ::std::cerr;
      cerr << "Unable to complete the test run." << endl;
    }
    return 0 == rc;
}

Itu sedikit ekstrem dengan hanya beberapa baris melakukan output, tetapi Anda mendapatkan idenya.

Hal lain yang bisa dilakukan adalah alias atau mengetik untuk meminimalkan pengetikan. Saya tidak menemukan std :: apa pun menjadi seburuk itu, tetapi kami memiliki seperangkat sumber besar dengan beberapa lusin modul dan terkadang kami harus menulis kode seperti console_gui::command_window::append("text"). Itu membosankan setelah beberapa saat dan menyebabkan banyak antrian panjang. Saya semua untuk sesuatu seperti

typedef console_gui::command_window cw;
cw::append("text");

selama alias dilakukan dalam lingkup lokal dan menjaga konteks yang cukup untuk membuat kode dapat dibaca.


1
Terima kasih! Ini sangat membantu. Anda tidak hanya menjelaskan mengapa itu buruk dengan contoh yang bagus, tetapi juga menunjukkan solusi dengan contoh yang bagus. :-)
Tuan Loh.

1
BTW: Menggunakan std::endluntuk flush eksplisit pada stdout/ stderrbiasanya cukup berlebihan, aliran tersebut terikat stdout/ stderrtoh. Bahkan sedikit memperlambatnya.
Deduplicator

8

Ini karena: 1) ia mengalahkan seluruh tujuan ruang nama, yaitu untuk mengurangi tabrakan nama; 2) itu membuat tersedia untuk namespace global yang seluruh namespace ditentukan dengan menggunakan direktif.

Misalnya, jika Anda memasukkan dan menetapkan fungsi maks () Anda sendiri, ia akan bertabrakan dengan std :: max ().

http://en.cppreference.com/w/cpp/algorithm/max

Preferensi adalah menggunakan std :: member_you_wish_to_use karena secara eksplisit menyatakan namespace yang akan digunakan.


Saya kira ini berarti saya harus menggunakan std::max()awalan ruang nama. Atau saya salah?
Tuan Loh.

3
Ini berarti bahwa jika Anda meletakkan "using namespace std;" dalam kode Anda, Anda akan mendapatkan kesalahan jika Anda mendefinisikan fungsi maks Anda sendiri (atau nama lain yang sudah didefinisikan di std namespace)
Chewy Gumball

1
Ini hanya berarti bahwa Anda harus berhati-hati dengan usingarahan karena dalam hal ini akan merusak fungsi max () Anda jika Anda telah mendefinisikan satu dan memasukkan <algorithm>. Ini adalah kasus sederhana tetapi Anda tidak pernah tahu apa yang mungkin Anda hancurkan. Anda harus mengetahui seluruh perpustakaan untuk memastikan Anda tidak merusaknya tetapi Anda tidak bisa tahu apakah kode Anda akan rusak (yaitu tabrakan nama) di masa depan.
ApplePie

6

Mengutip tautan yang Anda berikan:

Anda dapat menggunakan deklarasi penggunaan di mana saja dalam file .cc, dan dalam fungsi, metode atau kelas dalam file .h.

// OK dalam file .cc.

// Harus dalam fungsi, metode atau kelas dalam file .h.

menggunakan :: foo :: bar;

Gaya Google melarang Anda menggunakan mengimpor ruang nama dalam konteks global, tetapi memungkinkan untuk melakukannya dalam ruang lokal.

Di mana-mana di mana menggunakan deklarasi hanya memengaruhi bagian kode yang terbatas dan terlihat jelas itu sangat dapat diterima.

Saat Anda mencemari konteks global, kode yang tidak terkait akan terpengaruh (secara implisit menggunakan tajuk Anda). Tidak ada yang terjadi ketika Anda melakukannya dalam konteks lokal.


Kami memiliki standar yang sama. Beberapa orang kami secara lokal akan mengetik namespace yang panjang. mis. typedef foolicious :: barlicious fb; fb :: drink d;
Michael Mathews

1

mereka tidak merekomendasikan seseorang menggunakan namespace ornamespace: function` - jika saya tidak salah mengartikannya.

Anda melakukannya. Kekecewaan hanya berlaku untuk using namespacearahan (yang biasanya disebut abusing namespace, tidak sepenuhnya lucu). Sangat disarankan agar Anda menggunakan nama fungsi atau objek yang sepenuhnya memenuhi syarat, seperti std::cout.


1

Meskipun pertanyaannya sudah memiliki jawaban yang bermanfaat, satu detail tampaknya terlalu pendek.

Kebanyakan programmer pada awalnya agak bingung dengan usingkata kunci dan deskripsi namespacepenggunaan, bahkan jika mereka mencoba mempelajarinya dengan mencari referensi, karena deklarasi dan arahan berbunyi agak setara, keduanya kata-kata panjang yang relatif abstrak dimulai dengan d .

Pengidentifikasi dalam ruang nama dapat diakses dengan secara eksplisit memberi nama ruang nama:

myNamespace::myIdent

ini mungkin lebih banyak kunci untuk diketik. Tetapi juga dapat mengurangi signifikansi kode Anda, jika sebagian besar pengidentifikasi diawali dengan cara yang sama. Kata usingkunci membantu untuk mencegah kerugian namespace ini. Karena usingberfungsi pada level kompiler (ini bukan makro), efeknya berlaku untuk seluruh cakupan yang digunakan. Karena itulah gaya Google membatasi penggunaannya untuk cakupan yang didefinisikan dengan baik, yaitu kelas dalam file header atau fungsi dalam file cpp.

... tentu saja ada perbedaan di antara keduanya menggunakan deklarasi

using myNamespace::myIdent; // make myIdent an alias of myNamespace::myIdent

dan menggunakan arahan

using myNamespace; // make all identifiers of myNamespace directly accessible

Jika digunakan dalam lingkup besar, yang terakhir menyebabkan kebingungan lebih banyak .


1

Ini dia:

#include <iostream>

int main()
{
    std::endl(std::operator<<(std::cout, "Hello world!"));
}

Dengan menulis seperti ini, kami menghindari ADL rawan kesalahan bersama dengan menggunakan arahan dan deklarasi.

Ini dimaksudkan sebagai jawaban sarkastik. :-D

Saya dengan Herb Sutter melalui Google untuk yang satu ini. Dari C ++ Standar Pengodean:

Anda dapat dan harus menggunakan namespace menggunakan deklarasi dan arahan secara bebas dalam file implementasi Anda setelah #mengikutsertakan arahan dan merasa nyaman karenanya. Meskipun pernyataan berulang yang bertentangan, namespace menggunakan deklarasi dan arahan tidak jahat dan mereka tidak mengalahkan tujuan ruang nama. Sebaliknya, mereka adalah apa yang membuat ruang nama dapat digunakan .

Anda dapat terobsesi tentang potensi konflik namespace yang mungkin tidak akan pernah terwujud dan mungkin tidak akan sulit untuk diperbaiki dalam peristiwa yang jarang terjadi secara astronomis dengan secara hati-hati menghindari usingarahan dan secara eksplisit menentukan setiap hal yang Anda gunakan (turun ke operator) dengan usingdeklarasi, atau langsung saja dan mulai using namespace std. Saya merekomendasikan yang terakhir dari sudut pandang produktivitas.

Kebanyakan buku teks c ++ mengajarkan pemula dengan menggunakan namespace std; Apakah mereka menyebarkan praktik pengkodean yang buruk?

Sebaliknya jika Anda bertanya kepada saya, dan saya percaya Sutter di atas setuju.

Sekarang, selama karir saya, saya telah menemukan sekitar 3 konflik namespace total sebagai akibat langsung dari using arahan dalam basis kode yang mencakup puluhan juta LOC. Namun, dalam semua 3 kasus, mereka berada dalam file sumber yang membentang lebih dari 50.000 baris kode warisan, awalnya ditulis dalam C dan kemudian dibastardisasi ke C ++, melakukan daftar eklektik besar fungsi yang berbeda, termasuk header dari selusin perpustakaan yang berbeda, dan memiliki daftar epik #includesyang membentang di atas halaman. Terlepas dari kekacauan epik, mereka tidak terlalu sulit untuk diperbaiki karena mereka menyebabkan kesalahan build pada OSX (satu OS di mana kode gagal dibangun), bukan bug runtime. Jangan mengatur kode Anda dengan cara mengerikan ini dan Anda harus baik-baik saja.

Yang mengatakan, menghindari baik using arahan dan deklarasi di file header. Itu hanya terbelakang. Tetapi untuk file sumber, dan terutama file yang tidak memiliki halaman penuh dengan #includearahan, saya katakan jangan khawatirkan jika Anda tidak bekerja untuk Google.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.