Gunakan `menggunakan` dalam C ++ atau menghindarinya?

17

Diskon semantik yang berbeda karena ADL, bagaimana seharusnya saya gunakan secara umum using, dan mengapa? Apakah ini tergantung situasi (mis. Tajuk yang akan menjadi #included vs file sumber yang tidak akan)?

Juga, haruskah saya lebih suka ::std::atau std::?

  1. Namespace-level using namespace:

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  2. Menjadi sepenuhnya eksplisit:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
  3. Namespace-level using-declarations:

    using std::pair;
    using std::string;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  4. Function-local using-declarations:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using std::make_pair;
        return make_pair(s.begin(), s.end());
    }
  5. Fungsi-lokal using namespace:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using namespace std;
        return make_pair(s.begin(), s.end());
    }
  6. Sesuatu yang lain

Ini mengasumsikan pra-C ++ 14, dan dengan demikian tidak ada tipe pengembalian yang digunakan auto.

pengguna541686
sumber
2
Lihat stackoverflow.com/questions/1265039/using-std-namespace untuk titik awal.
Pemrogram
@AProgrammer: Ah, terima kasih atas tautannya, yang menjawab sebagian dari pertanyaan saya. :) Masih bertanya-tanya tentang ::std::vs std::sekalipun.
user541686
4
Saya menggunakan stdtanpa yang kedua sekalipun. Seseorang yang mendefinisikan namespace std meminta masalah (dan mungkin mencari untuk mengambil keuntungan yang kebanyakan orang gunakan stddan tidak ::std).
Pemrogram

Jawaban:

25

Hindari penggunaan usingdi header, karena itu merusak tujuan ruang nama.

Tidak apa-apa untuk menggunakannya dalam file sumber, tapi saya masih akan menghindarinya dalam beberapa kasus (misalnya using std).

Namun jika Anda mendapatkan ruang nama bersarang, tidak apa-apa:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A
BЈовић
sumber
6
+1 sungguh menakjubkan berapa banyak tutorial dan kursus di perguruan tinggi yang hanya memberi tahu Anda untuk menggunakan usingkata kunci tanpa penjelasan menyeluruh mengapa ruang nama digunakan untuk memulai.
Jeffrey Sweeney
Orang ingin melanjutkan menggunakan iostreams, string, dan sebagainya. Mereka tidak ingin harus mengetik std :: setiap kali mereka ingin menggunakan sesuatu, atau harus mengingat sepotong boilerplate untuk diletakkan di depan kode mereka, yang akan menyebabkan kesalahan yang kurang membantu jika mereka lupa . :(
Colen
Apakah sesuatu seperti typedef std :: string sstring; menjadi alternatif?
Giorgio
1
@Colen: Jiwa-jiwa malang ini dapat digunakan using std::coutdan berteman, tetapi tidak seperti coutitu sudah merupakan nama panjang yang mengerikan.
Benjamin Bannier
1
Jika Anda seorang mahasiswa di hari pertama "kelas C ++ pertama saya", itu adalah hal lain yang dapat menyebabkan kesalahan sintaks yang tidak Anda mengerti. Sangat mudah bagi kami untuk mencari tahu karena kami adalah programmer yang berpengalaman, tetapi ketika Anda mencoba untuk belajar bahasa, itu hal lain yang perlu dikhawatirkan adalah Anda tidak perlu.
Colen
11

Saat meletakkan pernyataan menggunakan dalam file sumber, TOLONG, cukup tarik hal-hal yang Anda butuhkan. Contohnya:

using std::string;
using std::ostringstream;

Masalahnya di sini adalah jika Anda melakukannya

using namespace std;

Anda menarik SETIAP HAL SINGLE dari std ke namespace global. Yang mengarah ke pesan kesalahan yang sangat menarik ketika Anda secara tidak sengaja menggunakan nama dalam kode Anda yang cocok dengan yang Anda sama sekali tidak sadari di std. Jika Anda hanya menarik hal-hal yang Anda inginkan, maka Anda tidak akan memiliki masalah itu (atau, lebih tepatnya, programmer berikutnya untuk mengerjakan kode Anda tidak akan memiliki masalah itu).

Michael Kohne
sumber
Atau, Anda bisa using namespacesaja dalam lingkup fungsi, menghindari masalah.
Tamás Szelei
2
@ Ikan - sebenarnya, melakukan 'menggunakan namespace' dalam lingkup fungsi tidak menghindari masalah, itu hanya membatasi ruang di mana hal-hal bisa salah. Dan jika Anda akhirnya menempatkan 'menggunakan namespace' di setiap fungsi, itu tidak jauh berbeda dari hanya melakukannya secara global.
Michael Kohne
Sementara C ++ memang memungkinkan seseorang untuk mendeklarasikan tipe pada level fungsi, itu bukan hal yang umum; selain itu, kemungkinan bentrokan nama mudah dikenali dari output kompiler (tetapi Anda benar bahwa ini tidak mencegahnya).
Tamás Szelei
2

Seperti yang ditunjukkan VJovic, jangan gunakan using dalam file header. usingdalam file header mempengaruhi unit kompilasi saat ini (file .cpp) dengan cara yang mungkin tidak diharapkan oleh file sumber.

using namespacejuga harus dihindari dalam file sumber. Ini membawa setiap simbol ke dalam cakupan yang sama dengan file sumber. Lebih jelas bagi pembaca Anda apa yang Anda lakukan jika Anda menggunakan simbol spesifik dari namespace.

Bill Door
sumber
2
Sebagai masalah praktis, kecuali kode Anda menimpa nama yang biasa digunakan, saya lebih suka melihat using namespace JoystickModuledi awal file .cpp daripada JoystickModule::dilampirkan ke setiap objek di seluruh.
Alex P
@ AlexP: Begitulah cara saya melakukannya. Satu usingpernyataan untuk namespace saya sendiri yang saat ini saya kerjakan dan yang lainnya tetap menggunakan namespace.
Benjamin Kloster
Saya harus menguraikan "menggunakan simbol khusus dari namespace". Daripada mengawali setiap simbol pada setiap penggunaan, yang tidak membantu keterbacaan, saya lebih suka menggunakan pengangkat simbol eksplisit. using SomeNameSpace::SomeSymbol. Ini menghindari memindahkan setiap simbol dari namespace ke dalam cakupan saat ini.
Bill Door
0

Menulis usingdi Header adalah cara terbaik untuk membuat semua jenis bug yang tidak menyenangkan dan tidak mungkin untuk debug . Jangan tidak melakukan hal ini.

Menulis using namespace XYZdi file sumber sedikit lebih baik, tetapi masih bisa menyebabkan Anda sakit kepala yang tak terhitung jumlahnya. Cara yang aman adalah menentukan apa yang Anda gunakan misalnya using Foo::Bar.

Katakanlah Anda memiliki Bar.cpp dengan yang berikut:

//Bar.cpp
using namespace Foo;
namespace
{
    double increment(double v) { return (v + 1); }
}

void Bar::someFunction()
{
    //...
    int currentIndex = 0;
    int nextIndex = increment(currentIndex);
    //...
}

Fungsi ini berfungsi dengan baik, sampai suatu hari - tampaknya tanpa perubahan kode di kelas yang relevan - perilakunya berubah: Tiba-tiba currentIndexsepertinya selalu dimatikan satu per satu . Menggali perubahan terbaru Anda tidak menemukan perubahan bahkan terkait dengan kode jarak jauh.

Akhirnya Anda menemukan penyebabnya:
Anda (secara tidak langsung) memasukkan Foo.hsuatu tempat. Dalam file untuk namespace Foo fungsi baru ditambahkan:

//Foo.h
namespace Foo
{
    //...
    int& increment(int& v) { v += 1; return v; };
    //...
}

Yang merupakan kecocokan yang lebih baik increment(int)daripada fungsi Anda increment(double)- jadi sekarang Foo::increment()fungsi dipanggil oleh Bar::someFunction(). Aduh.

(Dan jika Anda adalah untuk menulis usingdi Header yang using namespace Foomungkin sangat baik menjadi di mana saja di pohon termasuk Anda ...)

Jadi ... Jangan menulis apa pun usingdi Header, dan berhati-hatilah dalam menulis using namespacefile sumber.

CharonX
sumber