C ++ 'da "const" kaç ve hangileri kullanılır?


129

Acemi bir C ++ programcısı olarak, bana hala çok belirsiz görünen bazı yapılar var, bunlardan biri const. Onu pek çok yerde ve o kadar çok farklı efektle kullanabilirsiniz ki, yeni başlayanların canlı çıkması neredeyse imkansızdır. Bazı C ++ uzmanları çeşitli kullanımları sonsuza dek açıklayacak mı ve bunları kullanıp kullanmayacağını ve / veya neden kullanmayacağını?


tam olarak şu soruyu arıyor: D
alamin

Yanıtlar:


100

Bazı kullanımları toplamaya çalışıyorum:

Kullanım ömrünü uzatmak için bazı geçici olarak const'a başvurmak. Referans bir temel olabilir - ve onun yıkıcısının sanal olması gerekmez - doğru yıkıcı yine de denir:

ScopeGuard const& guard = MakeGuard(&cleanUpFunction);

Kod kullanarak açıklama :

struct ScopeGuard { 
    ~ScopeGuard() { } // not virtual
};

template<typename T> struct Derived : ScopeGuard { 
    T t; 
    Derived(T t):t(t) { }
    ~Derived() {
        t(); // call function
    }
};

template<typename T> Derived<T> MakeGuard(T t) { return Derived<T>(t); }

Bu numara Alexandrescu'nun ScopeGuard yardımcı program sınıfında kullanılır. Geçici kapsam dışına çıktığında, Derived'in yıkıcısı doğru şekilde çağrılır. Yukarıdaki kod bazı küçük ayrıntıları gözden kaçırıyor, ancak asıl önemli olan bu.


Diğer yöntemlerin bu nesnenin mantıksal durumunu değiştirmeyeceğini söylemek için const kullanın.

struct SmartPtr {
    int getCopies() const { return mCopiesMade; }
};

Derleyicinin ne zaman kopyalamanız gerekip gerekmediğine karar vermenize yardımcı olması için, yazma üzerine kopyalama sınıfları için const kullanın .

struct MyString {
    char * getData() { /* copy: caller might write */ return mData; }
    char const* getData() const { return mData; }
};

Açıklama : Orijinal ile kopyalanan nesnenin verileri aynı kaldığı sürece bir şeyi kopyaladığınızda verileri paylaşmak isteyebilirsiniz. Nesnelerden biri veriyi değiştirdiğinde, şimdi iki versiyona ihtiyacınız var: Biri orijinal, diğeri kopya için. Yani, bir yazıyı kopyalıyorsun her iki nesneye , böylece artık her ikisinin de kendi sürümleri olur.

Kodu kullanarak :

int main() {
    string const a = "1234";
    string const b = a;
    // outputs the same address for COW strings
    cout << (void*)&a[0] << ", " << (void*)&b[0];
}

Yukarıdaki kod parçası benim GCC'de aynı adresi yazdırır, çünkü kullanılan C ++ kitaplığı bir yazma üzerine kopyala uygular std::string. Her iki dizge de ayrı nesneler olsalar bile, dizgi verileri için aynı belleği paylaşır. bConst olmayan yapmak, const olmayan sürümünü tercih eder operator[]ve GCC, yedek bellek arabelleğinin bir kopyasını oluşturur, çünkü onu değiştirebiliriz ve a! ' Nin verilerini etkilememelidir .

int main() {
    string const a = "1234";
    string b = a;
    // outputs different addresses!
    cout << (void*)&a[0] << ", " << (void*)&b[0];
}

Copy-yapıcının const nesnelerinden ve geçicilerden kopya oluşturması için :

struct MyClass {
    MyClass(MyClass const& that) { /* make copy of that */ }
};

Önemsiz bir şekilde değiştirilemeyen sabitler yapmak için

double const PI = 3.1415;

Olası pahalı veya imkansız by-value geçişini önlemek için değer yerine referansla rastgele nesneler iletmek için

void PrintIt(Object const& obj) {
    // ...
}

2
Örneklerinizdeki birinci ve üçüncü kullanımı lütfen açıklayabilir misiniz?
tunnuz

"Aranan uca parametrenin NULL olamayacağını garanti etmek için" const'ın bu örnekle nasıl bir ilgisi olduğunu görmüyorum.
Logan Capaldo

oops, çok başarısız oldum. bir şekilde referanslar hakkında yazmaya başladım. inlediğiniz için çok teşekkür ederim :) tabi ki şimdi bunları kaldıracağım :)
Johannes Schaub - litb

3
Lütfen ilk örneği açıklayın. Bana pek mantıklı gelmiyor.
chikuba

28

C ++ 'da const'ın 2 ana kullanımı vardır.

Sabit değerler

Bir değer, ömrü boyunca değiştirilmeyecek (veya değiştirilmemesi gereken) bir değişken, üye veya parametre biçimindeyse, onu sabit olarak işaretlemelisiniz. Bu, nesne üzerindeki mutasyonları önlemeye yardımcı olur. Örneğin, aşağıdaki işlevde, geçirilen Student örneğini değiştirmeme gerek yoktur, böylece onu sabit olarak işaretlerim.

void PrintStudent(const Student& student) {
  cout << student.GetName();
}

Bunu neden yaptığına gelince. Altta yatan verilerin değişemeyeceğini biliyorsanız, bir algoritma hakkında mantık yürütmek çok daha kolaydır. "const" yardımcı olur, ancak bunun başarılacağını garanti etmez.

Açıkçası, verilerin cout'a yazdırılması fazla düşünmeyi gerektirmez :)

Bir üye yöntemini sabit olarak işaretleme

Önceki örnekte Öğrenci'yi sabit olarak işaretledim. Fakat C ++, öğrenci üzerinde GetName () yöntemini çağırmanın nesneyi değiştirmeyeceğini nereden biliyordu? Cevap, yöntemin sabit olarak işaretlenmiş olmasıdır.

class Student {
  public:
    string GetName() const { ... }
};

Bir yöntemi "const" olarak işaretlemek 2 şey yapar. Öncelikle C ++ 'ya bu yöntemin nesnemi değiştirmeyeceğini söyler. İkincisi, tüm üye değişkenlerin artık sabit olarak işaretlenmiş gibi ele alınacağıdır. Bu yardımcı olur, ancak sınıfınızın örneğini değiştirmenizi engellemez.

Bu son derece basit bir örnek ama umarım sorularınızı cevaplamaya yardımcı olur.


16

Bu 4 beyan arasındaki farkı anlamaya özen gösterin:

Aşağıdaki 2 bildirim anlamsal olarak aynıdır. Ccp1 ve ccp2'nin nerede olduğunu değiştirebilirsiniz , ancak işaret ettikleri şeyi değiştiremezsiniz.

const char* ccp1;
char const* ccp2;

Daha sonra, işaretçi sabittir, bu nedenle anlamlı olması için bir şeyi gösterecek şekilde başlatılması gerekir. Sen buna işaret, başka bir şeye ancak şeyi işaret yapamaz olabilir değiştirilebilir.

char* const cpc = &something_possibly_not_const;

Son olarak, ikisini birleştiriyoruz - böylece işaret edilen şey değiştirilemez ve işaretçi başka bir yere işaret edemez.

const char* const ccpc = &const_obj;

Saat yönünde spiral kuralı, bir bildirimin çözülmesine yardımcı olabilir http://c-faq.com/decl/spiral.anderson.html


Dolambaçlı bir şekilde, evet öyle! Saat yönünde sarmal kuralı bunu daha iyi açıklar - addan (kpPointer) başlayın ve belirteçten geçen saat yönünde bir sarmal çizin ve her belirteci söyleyin. Açıkçası, kpPointer'ın sağında hiçbir şey yok ama yine de çalışıyor.
Steve Folly

3

Küçük bir not olarak, burada okuduğum gibi , şunu fark etmek faydalı

const onun hemen solunda olan şey için geçerlidir (orada hiçbir şey olmaması dışında, bu durumda, onun hemen sağındaki şey için geçerlidir).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.