Fitur C ++ adalah kemampuan untuk membuat ruang nama tanpa nama (anonim), seperti:
namespace {
int cannotAccessOutsideThisFile() { ... }
} // namespace
Anda akan berpikir bahwa fitur seperti itu akan sia-sia - karena Anda tidak dapat menentukan nama namespace, tidak mungkin untuk mengakses apa pun di dalamnya dari luar. Tetapi ruang nama yang tidak disebutkan namanya ini dapat diakses di dalam file tempat mereka dibuat, seolah-olah Anda memiliki klausa penggunaan implisit kepadanya.
Pertanyaan saya adalah, mengapa atau kapan ini lebih disukai daripada menggunakan fungsi statis? Atau apakah mereka pada dasarnya dua cara melakukan hal yang persis sama?
c++
namespaces
Kepala Geek
sumber
sumber
static
dalam konteks ini tidak dihargai ; meskipun namespace yang tidak disebutkan namanya adalah alternatif yang unggulstatic
, ada contoh di mana ia gagal ketikastatic
datang untuk menyelamatkan .Jawaban:
Standar C ++ membaca di bagian 7.3.1.1 Ruang nama yang tidak disebutkan namanya, paragraf 2:Statis hanya berlaku untuk nama objek, fungsi, dan serikat anonim, bukan untuk mengetik deklarasi.
Edit:
Keputusan untuk menghentikan penggunaan kata kunci statis ini (memengaruhi visibilitas deklarasi variabel dalam unit terjemahan) telah dibatalkan ( ref ). Dalam hal ini menggunakan namespace statis atau tanpa nama kembali ke dasarnya dua cara melakukan hal yang sama persis. Untuk diskusi lebih lanjut silakan lihat pertanyaan SO ini .
Ruang nama yang tidak disebutkan namanya masih memiliki keuntungan memungkinkan Anda untuk menentukan jenis terjemahan-unit-lokal. Silakan lihat pertanyaan SO ini untuk lebih jelasnya.
Penghargaan diberikan kepada Mike Percy karena telah menyampaikan ini kepada saya.
sumber
namespace
s secara implisit memiliki hubungan internal, jadi seharusnya tidak ada perbedaan. Setiap masalah yang sebelumnya mungkin muncul dari kata-kata yang buruk diselesaikan dengan menjadikan ini persyaratan dalam C ++ 11.Menempatkan metode dalam ruang nama anonim mencegah Anda dari melanggar Aturan Satu Definisi , memungkinkan Anda untuk tidak pernah khawatir tentang penamaan metode pembantu Anda sama seperti beberapa metode lain yang mungkin Anda tautkan.
Dan, seperti yang ditunjukkan oleh Lukas, ruang nama anonim lebih disukai oleh standar daripada anggota statis.
sumber
Ada satu kasus tepi di mana statis memiliki efek yang mengejutkan (setidaknya bagi saya). Standar C ++ 03 menyatakan dalam 14.6.4.2/1:
Kode di bawah ini akan memanggil
foo(void*)
dan bukanfoo(S const &)
seperti yang Anda harapkan.Dalam dirinya sendiri ini mungkin bukan masalah besar, tetapi itu menyoroti bahwa untuk kompiler C ++ sepenuhnya kompatibel (yaitu satu dengan dukungan untuk
export
)static
kata kunci masih akan memiliki fungsi yang tidak tersedia dengan cara lain.Satu-satunya cara untuk memastikan bahwa fungsi di namespace kami yang tidak disebutkan namanya tidak akan ditemukan dalam template menggunakan ADL adalah dengan membuatnya
static
.Pembaruan untuk C ++ Modern
Pada C ++ '11, anggota namespace yang tidak disebutkan namanya memiliki hubungan internal secara implisit (3.5 / 4):
Tetapi pada saat yang sama, 14.6.4.2/1 telah diperbarui untuk menghapus penyebutan tautan (ini diambil dari C ++ '14):
Hasilnya adalah bahwa perbedaan khusus antara anggota namespace statis dan tidak bernama tidak ada lagi.
sumber
NS::S
bekerja, tidakS
perlu tidak ada di dalamnamespace {}
?Saya baru-baru ini mulai mengganti kata kunci statis dengan ruang nama anonim dalam kode saya tetapi segera mengalami masalah di mana variabel dalam namespace tidak lagi tersedia untuk diperiksa di debugger saya. Saya menggunakan VC60, jadi saya tidak tahu apakah itu bukan masalah dengan debugger lain. Solusi saya adalah mendefinisikan namespace 'modul', di mana saya memberinya nama file cpp saya.
Misalnya, dalam file XmlUtil.cpp saya, saya mendefinisikan namespace
XmlUtil_I { ... }
untuk semua variabel dan fungsi modul saya. Dengan begitu saya bisa menerapkanXmlUtil_I::
kualifikasi di debugger untuk mengakses variabel. Dalam hal ini,_I
membedakannya dari namespace publik sepertiXmlUtil
yang mungkin ingin saya gunakan di tempat lain.Saya kira kelemahan potensial dari pendekatan ini dibandingkan dengan yang benar-benar anonim adalah bahwa seseorang dapat melanggar ruang lingkup statis yang diinginkan dengan menggunakan kualifikasi namespace di modul lain. Saya tidak tahu apakah itu merupakan perhatian utama.
sumber
#if DEBUG namespace BlahBlah_private { #else namespace { #endif
, jadi "module namespace" hanya ada di debug builds dan namespace anonim true digunakan sebaliknya. Alangkah baiknya jika debuggers memberi cara yang bagus untuk menangani ini. Doxygen juga bingung karenanya.Penggunaan kata kunci statis untuk tujuan itu sudah usang dengan standar C ++ 98. Masalah dengan statis adalah bahwa itu tidak berlaku untuk definisi tipe. Itu juga kata kunci kelebihan beban yang digunakan dalam berbagai cara dalam konteks yang berbeda, jadi ruang nama yang tidak disebutkan namanya menyederhanakan sedikit hal.
sumber
Dari pengalaman saya hanya akan mencatat bahwa sementara itu adalah cara C ++ untuk menempatkan fungsi-fungsi yang sebelumnya statis ke dalam namespace anonim, kompiler lama kadang-kadang dapat memiliki masalah dengan ini. Saat ini saya bekerja dengan beberapa kompiler untuk platform target kami, dan kompiler Linux yang lebih modern baik-baik saja dengan menempatkan fungsi ke dalam namespace anonim.
Tetapi kompiler lama yang berjalan pada Solaris, yang kita nantikan sampai rilis mendatang yang tidak ditentukan, kadang-kadang akan menerimanya, dan di lain waktu menandainya sebagai kesalahan. Kesalahannya bukan yang membuat saya khawatir, itu apa yang mungkin dilakukannya ketika menerimanya . Jadi sampai kita menjadi modern secara keseluruhan, kita masih menggunakan fungsi statis (biasanya kelas-lingkup) di mana kita lebih suka namespace anonim.
sumber
Selain itu jika seseorang menggunakan kata kunci statis pada variabel seperti contoh ini:
Itu tidak akan terlihat di file pemetaan
sumber
Perbedaan spesifik kompiler antara ruang nama anonim dan fungsi statis dapat dilihat dengan mengkompilasi kode berikut.
Kompilasi kode ini dengan VS 2017 (menentukan flag peringatan level 4 / W4 untuk mengaktifkan peringatan C4505: fungsi lokal yang tidak direferensikan telah dihapus ) dan gcc 4.9 dengan fungsi -Wunused-function atau -Wall menunjukkan bahwa VS 2017 hanya akan menghasilkan peringatan untuk fungsi statis yang tidak digunakan. gcc 4.9 dan lebih tinggi, serta dentang 3.3 dan lebih tinggi, akan menghasilkan peringatan untuk fungsi yang tidak direferensikan dalam namespace dan juga peringatan untuk fungsi statis yang tidak digunakan.
Demo langsung gcc 4.9 dan MSVC 2017
sumber
Secara pribadi saya lebih suka fungsi statis daripada ruang nama tanpa nama untuk alasan berikut:
Jelas dan jelas dari definisi fungsi saja bahwa itu pribadi untuk unit terjemahan di mana ia dikompilasi. Dengan namespace tanpa nama, Anda mungkin perlu menggulir dan mencari untuk melihat apakah suatu fungsi ada dalam namespace.
Fungsi dalam ruang nama mungkin diperlakukan sebagai eksternal oleh beberapa kompiler (yang lebih tua). Dalam VS2017 mereka masih eksternal. Untuk alasan ini bahkan jika suatu fungsi berada dalam namespace tanpa nama, Anda mungkin masih ingin menandainya sebagai statis.
Fungsi statis berperilaku sangat mirip dalam C atau C ++, sedangkan ruang nama tanpa nama jelas hanya C ++. ruang nama tanpa nama juga menambahkan level tambahan dalam indentasi dan saya tidak suka itu :)
Jadi, saya senang melihat bahwa penggunaan statis untuk fungsi tidak lagi usang .
sumber
static
kata kunci yang benar-benar menerapkan tautan lokal ke suatu fungsi. Juga, tentunya hanya orang gila yang mengoceh yang benar-benar akan menambahkan lekukan untuk ruang nama?Setelah mempelajari fitur ini barusan saat membaca pertanyaan Anda, saya hanya bisa berspekulasi. Ini tampaknya memberikan beberapa keunggulan dibandingkan variabel statis tingkat file:
Saya akan tertarik mempelajari apakah ada yang menggunakan ruang nama anonim dalam kode nyata.
sumber
Perbedaannya adalah nama pengidentifikasi hancur (
_ZN12_GLOBAL__N_11bE
vs_ZL1b
, yang tidak terlalu penting, tetapi keduanya dirakit menjadi simbol lokal dalam tabel simbol (tidak adanya.global
arahan asm).Adapun ruang nama anonim bersarang:
Semua ruang nama anonim tingkat 1 di unit terjemahan digabungkan satu sama lain, Semua ruang nama anonim bersarang tingkat 2 di unit terjemahan digabungkan satu sama lain
Anda juga dapat memiliki namespace bersarang (sebaris) di namespace anonim
Anda juga dapat memiliki ruang nama sebaris anonim, tetapi sejauh yang saya tahu,
inline
pada ruang nama anonim memiliki 0 efek_ZL1b
:_Z
berarti ini adalah pengidentifikasi yang rusak.L
berarti itu adalah simbol lokalstatic
.1
adalah panjang pengidentifikasib
dan kemudian pengidentifikasib
_ZN12_GLOBAL__N_11aE
_Z
berarti ini adalah pengidentifikasi yang rusak.N
berarti ini adalah namespace12
adalah panjang nama namespace anonim_GLOBAL__N_1
, maka nama namespace anonim_GLOBAL__N_1
, kemudian1
panjang pengidentifikasia
,a
adalah pengidentifikasia
danE
menutup pengidentifikasi yang berada di namespace._ZN12_GLOBAL__N_11A1aE
sama seperti di atas kecuali ada level namespace lain di dalamnya1A
sumber