Di semua kursus c ++ kami, semua pengajar selalu meletakkan using namespace std;
tepat setelah #include
s di .h
file mereka . Bagi saya ini menjadi berbahaya sejak saat itu dengan memasukkan header itu ke dalam program lain, saya akan mendapatkan namespace yang diimpor ke program saya, mungkin tanpa disadari, disengaja atau diinginkan (penyertaan header bisa sangat bersarang).
Jadi pertanyaan saya adalah dua kali lipat: Apakah saya benar yang using namespace
tidak boleh digunakan dalam file header, dan / atau adakah cara untuk membatalkannya, seperti:
//header.h
using namespace std {
.
.
.
}
Satu pertanyaan lagi di sepanjang baris yang sama: Haruskah file header #include
semua header yang dibutuhkan .cpp
file yang sesuai, hanya yang diperlukan untuk definisi header dan membiarkan .cpp
file #include
sisanya, atau tidak ada dan menyatakan semua yang dibutuhkannya sebagai extern
?
Alasan di balik pertanyaan tersebut sama seperti di atas: Saya tidak ingin kejutan ketika menyertakan .h
file.
Juga, jika saya benar, apakah ini kesalahan umum? Maksud saya dalam pemrograman dunia nyata dan dalam proyek "nyata" di luar sana.
Terima kasih.
sumber
using namespace
pernyataan maka Anda dapat menggunakan nama yang memenuhi syarat untuk menyelesaikan masalah.Jawaban:
Anda sebaiknya TIDAK menggunakan
using namespace
header karena alasan yang Anda katakan, bahwa hal itu dapat secara tidak terduga mengubah arti kode di file lain yang menyertakan header itu. Tidak ada cara untuk membatalkanusing namespace
yang merupakan alasan lain mengapa itu sangat berbahaya. Saya biasanya hanya menggunakangrep
atau sejenisnya untuk memastikan bahwausing namespace
tidak disebutkan di header daripada mencoba sesuatu yang lebih rumit. Mungkin pemeriksa kode statis menandai ini juga.Header harus menyertakan hanya header yang perlu dikompilasi. Cara mudah untuk menerapkannya adalah dengan selalu menyertakan header setiap file sumber sebagai hal pertama, sebelum header lainnya. Kemudian file sumber akan gagal untuk dikompilasi jika header tidak berdiri sendiri. Dalam beberapa kasus, misalnya merujuk ke kelas detail implementasi dalam perpustakaan, Anda dapat menggunakan deklarasi maju daripada
#include
karena Anda memiliki kontrol penuh atas definisi kelas yang dideklarasikan maju tersebut.Saya tidak yakin saya akan menyebutnya biasa, tetapi pasti muncul sesekali, biasanya ditulis oleh programmer baru yang tidak menyadari konsekuensi negatifnya. Biasanya hanya sedikit pendidikan tentang risiko yang menangani masalah apa pun karena relatif mudah untuk diperbaiki.
sumber
using
pernyataan dalam.cpp
file kita ? yang3rdPartyLib::BigClassName<3rdPartyLib::AnotherBigName,3rdPartyLib::AnotherBigName>::Iterator
s adalah kematian ke ujung jari.template
fungsi - yang seharusnya ada di header?typedefs
?using
pernyataan di dalam.cpp
file tanpa banyak perhatian karena cakupan akan terbatas hanya pada file itu, tetapi jangan pernah melakukannya sebelum#include
pernyataan. Adapun fungsi template yang didefinisikan dalam header, sayangnya saya tidak tahu solusi yang baik selain hanya menulis namespace ... Mungkin Anda dapat meletakkanusing
deklarasi dalam ruang lingkup terpisah{ /* using statement in between brackets */ }
, yang setidaknya akan mencegahnya keluar dari file saat ini .Butir 59 dalam Sutter dan Alexandrescu's "C ++ Coding Standards: 101 Rules, Guidelines, and Best Practices" :
File header adalah tamu di satu atau beberapa file sumber. File header yang menyertakan
using
arahan dan deklarasi membawa teman-temannya yang gaduh juga.Sebuah
using
deklarasi membawa satu teman. Sebuahusing
direktif membawa semua teman di namespace. Penggunaan guru Andausing namespace std;
adalah menggunakan direktif.Lebih serius lagi, kami memiliki ruang nama untuk menghindari benturan nama. File header dimaksudkan untuk menyediakan antarmuka. Sebagian besar header bersifat agnostik terhadap kode apa yang mungkin menyertakannya, sekarang atau di masa mendatang. Menambahkan
using
pernyataan untuk kenyamanan internal dalam tajuk memasukkan nama-nama yang mudah digunakan itu pada semua klien potensial tajuk itu. Itu bisa menyebabkan bentrokan nama. Dan itu tidak sopan.sumber
Anda harus berhati-hati saat menyertakan header di dalam header. Dalam proyek besar, ini dapat membuat rantai ketergantungan yang sangat kusut yang memicu pembangunan kembali yang lebih besar / lebih lama dari yang sebenarnya diperlukan. Lihat artikel ini dan tindak lanjutnya untuk mempelajari lebih lanjut tentang pentingnya struktur fisik yang baik dalam proyek C ++.
Anda sebaiknya hanya menyertakan header di dalam header saat benar-benar dibutuhkan (kapan pun definisi lengkap kelas diperlukan), dan gunakan deklarasi maju di mana pun Anda bisa (saat kelas yang dibutuhkan adalah pointer atau referensi).
Sedangkan untuk ruang nama, saya cenderung menggunakan cakupan ruang nama eksplisit di file header saya, dan hanya meletakkan a
using namespace
di file cpp saya.sumber
template
deklarasi fungsi? yang harus terjadi di header, bukan?Lihat standar pengkodean Goddard Space Flight Center (untuk C dan C ++). Itu ternyata sedikit lebih sulit dari sebelumnya - lihat jawaban terbaru untuk pertanyaan SO:
Standar pengkodean GSFC C ++ mengatakan:
Pertanyaan pertama dari pertanyaan referensi silang sekarang menyertakan kutipan dari standar pengkodean GSFC C, dan alasannya, tetapi substansinya akhirnya sama.
sumber
Anda benar bahwa
using namespace
sundulan berbahaya. Saya tidak tahu bagaimana cara membatalkannya. Sangat mudah untuk mendeteksinya namun hanya mencariusing namespace
di file header. Karena alasan terakhir itu, hal ini jarang terjadi dalam proyek nyata. Rekan kerja yang lebih berpengalaman akan segera mengeluh jika seseorang melakukan hal seperti itu.Dalam proyek nyata orang mencoba meminimalkan jumlah file yang disertakan, karena semakin sedikit Anda memasukkan, semakin cepat kompilasi. Itu menghemat waktu semua orang. Namun jika file header mengasumsikan bahwa sesuatu harus disertakan sebelumnya, maka file itu harus menyertakannya sendiri. Jika tidak, itu membuat header tidak mandiri.
sumber
Kamu benar. Dan file apa pun hanya boleh menyertakan header yang dibutuhkan oleh file itu. Adapun "apakah melakukan sesuatu yang salah adalah hal biasa dalam proyek dunia nyata?" - Oh ya!
sumber
Seperti semua hal dalam pemrograman, pragmatisme harus menang atas dogmatisme, IMO.
Selama Anda membuat keputusan di seluruh proyek ("Proyek kami menggunakan STL secara ekstensif, dan kami tidak ingin harus menambahkan semuanya dengan std ::."), Saya tidak melihat ada masalah dengan itu. Satu-satunya hal yang Anda pertaruhkan adalah bentrokan nama, dan dengan keberadaan STL di mana-mana itu tidak mungkin menjadi masalah.
Di sisi lain, jika itu adalah keputusan oleh satu pengembang dalam satu file header (non-pribadi), saya dapat melihat bagaimana hal itu akan menimbulkan kebingungan di antara tim dan harus dihindari.
sumber
Berkenaan dengan "Apakah ada cara untuk membatalkan [
using
pernyataan]?"Saya pikir akan berguna untuk menunjukkan bahwa
using
deklarasi dipengaruhi oleh ruang lingkup.Sangat efektif ya. Dengan membatasi ruang lingkup
using
deklarasi, efeknya hanya bertahan dalam ruang lingkup itu; itu 'dibatalkan' saat cakupan itu berakhir.Ketika
using
deklarasi dideklarasikan dalam file di luar cakupan lain, ia memiliki cakupan file dan memengaruhi semua yang ada di file itu.Dalam kasus file header, jika
using
deklarasi berada pada cakupan file, ini akan meluas ke cakupan file apa pun yang termasuk dalam header.sumber
namespace
hal-hal deklarasi) vs bagaimana sebenarnya bekerja (seperti variabel).{}
melampirkannya membatasi ruang lingkupnya,{}
setelah ia tidak melakukan apa pun yang berhubungan dengannya. Itu adalah cara yang tidak disengajausing namespace
diterapkan secara global.Saya yakin Anda dapat menggunakan 'using' di header C ++ dengan aman jika Anda menulis deklarasi di namespace bersarang seperti ini:
Ini harus mencakup hanya hal-hal yang dideklarasikan dalam 'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED' tanpa ruang nama yang digunakan. Saya telah mengujinya pada kompiler mingw64.
sumber
using
deklarasi di dalam definisi fungsi di mana saya bisa sehingga mereka tidak akan mencemari ruang nama di luar fungsi. Tapi sekarang saya ingin menggunakan literal yang ditentukan pengguna C ++ 11 dalam file header, dan sesuai dengan konvensi biasa, operator literal dilindungi oleh namespace; tetapi saya tidak ingin menggunakannya dalam daftar penginisialisasi konstruktor yang tidak berada dalam cakupan yang dapat saya gunakan denganusing
deklarasi non-polusi . Jadi ini bagus untuk memecahkan masalah itu.error: ... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED:: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED::ClassName ...
. Setidaknya, itulah yang terjadi pada saya di g ++.