const (bilgisayar programlama) - const (computer programming)

In C , C ++ , D , JavaScript ve Julia programlama dilleri , const bir olan tip niteleyici : Bir kelime bir uygulanan veri türü veri salt okunur olduğunu gösterir. Bu iken bildirmek için kullanılabilecek sabitleri , const bir parçası olmakla diğer dillerde benzer yapılarından diller farklıdır C ailede tip, ve böylece birleştirildiğinde davranışı karmaşık hale getirdi işaretçiler , referanslar, kompozit veri türleri ve tip denetimi.

Giriş

Bir nesne bildiriminde uygulandığında , nesnenin sabit olduğunu gösterir : bir değişkenin aksine değeri değiştirilemez . Bu temel kullanım - sabitleri bildirmek için - diğer birçok dilde paralelliklere sahiptir.

Bununla birlikte, diğer dillerden farklı olarak, C dil ailesinde , nesnenin bir parçası değil const , türün bir parçasıdır . Örneğin, C, bir nesne bildirir ve - Çeşidi - bu ayrıştırıldı gibi, tip bir parçası olan "(int sabit) x" ise Ada , bir sabit (nesnenin bir tür) bildirir arasında : türü olan nesnenin bir parçası , ancak türün bir parçası değil . int const x = 1;xint constconstX : constant INTEGER := 1_XINTEGERconstant

Bunun iki ince sonucu vardır. İlk olarak, const daha karmaşık bir türün parçalarına uygulanabilir - örneğin, int const * const x; sabit bir tam sayıya sabit bir işaretçi bildirirken, sabit bir tam sayıya int const * x; değişken bir işaretçi int * const x; bildirir ve bir değişken tam sayıya sabit bir işaretçi bildirir. İkinci olarak, const türün bir parçası olduğu için, tür kontrolünün bir parçası olarak eşleşmesi gerekir. Örneğin, aşağıdaki kod geçersizdir:

void f(int& x);
// ...
int const i;
f(i);

argüman çünkü f bir olmalı değişken tamsayı, ancak i bir olan sabit tamsayı. Bu eşleştirme, bir program doğruluğu biçimidir ve sabit doğruluk olarak bilinir . Bu, sözleşmeye göre programlamaya izin verir , burada işlevler , bağımsız değişkenlerini değiştirip değiştirmediklerini ve dönüş değerlerinin değiştirilebilir olup olmadığını tür imzalarının bir parçası olarak belirtir . Bu tür denetimi, esasen işaretçiler ve referanslarla ilgilenir - tamsayılar gibi temel değer türleri değil - aynı zamanda bileşik veri türleri veya kapsayıcılar gibi şablonlu türler için de geçerlidir . Tür zorlaması (örtük tür dönüşümü ) ve C'nin değere göre çağrı olması (C ++ ve D, değere göre çağrı veya başvuruya göre çağrıdır ) nedeniyle genellikle ihmal edilebileceği gerçeğiyle gizlenmiştir . const

Sonuçlar

Sabitlik fikri, değişkenin bilgisayar belleğinde depolandığı için yazılamaz olduğu anlamına gelmez. Aksine, const -lık bir olan derleme zamanı bir programcı belirtir yapı olmalıdır ille onlar ne yapmak olabilir yapmak. Bununla birlikte, bu (örneğin önceden tanımlanmış veri durumunda char const * dizgilerin ), Cı const olup genelde olarak içeriği.

Sabitlerden ayrım

Program çalışırken bir sabit değerini değiştirmezken, bildirilen bir nesne const program çalışırken değerini gerçekten değiştirebilir. Yaygın bir örnek, dijital bir girişin mevcut durumu gibi, gömülü sistemlerdeki salt okunur kayıtlardır. Dijital girişler için veri kayıtları genellikle const ve olarak ilan edilir volatile . Bu kayıtların içeriği, program herhangi bir şey yapmadan değişebilir ( volatile ) ancak siz de onlara yazmayacaksınız ( const ).

Diğer kullanımlar

Ek olarak, bir (statik olmayan) üye işlevi olarak bildirilebilir const . Bu durumda, böyle bir işlevin içindeki this işaretçi object_type const * sadece tipten ziyade tiptedir object_type * . Bu, bu nesne için const olmayan işlevlerin böyle bir işlevin içinden çağrılamayacağı ve üye değişkenlerin değiştirilemeyeceği anlamına gelir. C ++ 'da, bir üye değişkeni, mutable bu kısıtlamanın kendisi için geçerli olmadığını gösterecek şekilde bildirilebilir . Bazı durumlarda bu yararlı olabilir, örneğin önbelleğe alma , referans sayma ve veri senkronizasyonu ile . Bu durumlarda, nesnenin mantıksal anlamı (durumu) değişmez, ancak bitsel gösterimi değişebileceğinden nesne fiziksel olarak sabit değildir.

Sözdizimi

C, C ++ ve D'de, kullanıcı tarafından tanımlananlar da dahil olmak üzere tüm veri türleri bildirilebilir const ve sabit-doğruluk, tüm değişkenlerin veya nesnelerin değiştirilmeleri gerekmedikçe bu şekilde bildirilmesi gerektiğini belirtir. Bu tür proaktif kullanımı, const değerlerin "anlaşılmasını, izlenmesini ve akıl yürütmesini kolaylaştırır" ve böylece kodun okunabilirliğini ve anlaşılabilirliğini artırır ve bir değerin amaçlanan kullanımı hakkında bilgi ilettiği için ekipler halinde çalışmayı ve kodun bakımını kolaylaştırır. Bu, kod hakkında akıl yürütürken derleyiciye ve geliştiriciye yardımcı olabilir . Ayrıca, optimize edici bir derleyicinin daha verimli kod üretmesini sağlayabilir .

Basit veri türleri

İşaretçi olmayan basit veri türleri için const niteleyicinin uygulanması basittir. Tarihsel nedenlerle bazı türlerin her iki tarafına da gidebilir (örneğin const char foo = 'a'; eşdeğerdir char const foo = 'a'; ). Bazı uygulamalarda, const iki kez kullanmak (örneğin const char const veya char const const ) bir uyarı oluşturur ancak bir hata oluşturmaz.

İşaretçiler ve referanslar

İşaretçi ve başvuru türleri için anlamı const daha karmaşıktır - işaretçinin kendisi veya işaret edilen değer veya her ikisi de olabilir const . Dahası, sözdizimi kafa karıştırıcı olabilir. Bir işaretçi, const yazılabilir bir değere işaretçi, bir const değere yazılabilir bir işaretçi veya bir değere const işaretçi olarak bildirilebilir const . Bir const gösterici, başlangıçta atanmış farklı bir nesneye noktasına yeniden edilemez, fakat bu (denilen işaret eden değerini değiştirmek için kullanılabilir pointee ). C ++ 'daki referans değişkenleri, const işaretçiler için alternatif bir sözdizimidir . const Öte yandan, bir nesneye yönelik bir işaretçi , başka bir bellek konumunu işaret edecek şekilde yeniden atanabilir (bu, aynı türde veya dönüştürülebilir türde bir nesne olmalıdır), ancak işaret ettiği belleği değiştirmek için kullanılamaz. için. Bir nesneye const yönelik bir işaretçi const de bildirilebilir ve nokta değiştirmek için kullanılamaz veya başka bir nesneyi işaret etmek için yeniden atanamaz. Aşağıdaki kod, bu incelikleri göstermektedir:

void Foo( int * ptr,
          int const * ptrToConst,
          int * const constPtr,
          int const * const constPtrToConst )
{
    *ptr = 0; // OK: modifies the "pointee" data
    ptr  = NULL; // OK: modifies the pointer

    *ptrToConst = 0; // Error! Cannot modify the "pointee" data
    ptrToConst  = NULL; // OK: modifies the pointer

    *constPtr = 0; // OK: modifies the "pointee" data
    constPtr  = NULL; // Error! Cannot modify the pointer

    *constPtrToConst = 0; // Error! Cannot modify the "pointee" data
    constPtrToConst  = NULL; // Error! Cannot modify the pointer
}

C sözleşmesi

Bildirimler için olağan C kuralını takiben, bildirim kullanımı izler ve * in a gösterici, başvuruyu kaldırmayı gösterecek şekilde işaretçi üzerine yazılır . Örneğin, bildiriminde int *ptr , dereferenced şekilde *ptr bir bir int referans şekilde ise, ptr bir işaretçi için int . Böylece adı sağa const değiştirir . C ++ kuralı, bunun yerine türü ile olduğu gibi ilişkilendirmek ve soldaki türü değiştirerek olarak okumaktır . bu nedenle " eşittir " (değer sabittir) veya " bir " (işaretçi sabit bir tam sayıya göstericidir ) olarak okunabilir . Böylece: *int* ptr,constint const * ptrToConst*ptrToConstint constptrToConstint const *

int *ptr; // *ptr is an int value
int const *ptrToConst; // *ptrToConst is a constant (int: integer value)
int * const constPtr; // constPtr is a constant (int *: integer pointer)
int const * const constPtrToConst; // constPtrToConst is a constant (pointer)
                                   // as is *constPtrToConst (value)

C ++ kuralı

Değeri değil, türü analiz etmeye yönelik C ++ kuralına uygun olarak , beyanı sağdan sola okumak için pratik bir kural vardır . Böylece, yıldızın solundaki her şey pointee türü olarak tanımlanabilir ve yıldızın sağındaki her şey işaretçi özellikleridir. Örneğin, yukarıdaki örneğimizde, int const * yazılabilir olmayan bir tam sayıya atıfta bulunan yazılabilir bir işaretçi int * const olarak okunabilir ve yazılabilir bir tam sayıya atıfta bulunan yazılamaz bir işaretçi olarak okunabilir.

Karmaşık bildirimleri ve tanımları anlamanıza yardımcı olan daha genel bir kural şu ​​şekilde çalışır:

  1. beyanını anlamak istediğiniz tanımlayıcıyı bulun
  2. mümkün olduğunca sağa doğru okuyun (yani, bildirimin sonuna veya sonraki kapanış parantezine kadar, hangisi önce gelirse)
  3. başladığınız yere geri dönün ve sola doğru geriye doğru okuyun (yani, bildirimin başlangıcına kadar veya önceki adımda bulunan kapanış paranteziyle eşleşen açık paranteze kadar)
  4. Beyannamenin başlangıcına ulaştığınızda bitirdiniz. Değilse, en son eşleşen kapanış parantezinin ötesinde 2. adıma geçin.

İşte bir örnek:

İfadenin bir parçası
double (**const (*fun(int))(double))[10]
Anlam
(aşağı doğru okuma)
Tanımlayıcı
                  fun
fun bir ...
Sağa doğru oku
                     (int))
işlev bir int bekliyor ...
Eşleşen bul (
                (*
bir işaretçi döndürmek ...
Sağdan devam edin
                           (double))
çift ​​bekleyen bir fonksiyon ...
Eşleşen bul (
        (**const
sabit bir işaretçiyi
bir işaretçiye döndürmek ...
Sağdan devam edin
                                    [10]
10'luk bloklar ...
Sola doğru oku
double
çiftler.

Sola doğru okurken, öğeleri sağdan sola doğru okumanız önemlidir. Böylece bir int const * , bir int için bir const işaretçisi değil, bir const int için bir işaretçi olur .

Bazı durumlarda C / C ++, const anahtar kelimenin türün soluna yerleştirilmesine izin verir . İşte bazı örnekler:

const int *ptrToConst;            //identical to: int const *ptrToConst,
const int *const constPtrToConst; //identical to: int const *const constPtrToConst

C / C ++ bu tür tanımlara izin verse de (tanımları soldan sağa okurken İngilizce diliyle yakından eşleşir), derleyici yine de yukarıda belirtilen prosedüre göre tanımları okur: sağdan sola. Ancak sabit olması gerekenin const önüne koymak , yazmayı düşündüğünüz şeyle derleyicinin yazdığınıza karar verdiği şey arasında hızlı bir şekilde uyumsuzluklar ortaya çıkarır. İşaretçiler için işaretçileri düşünün:

int **ptr;            // a pointer to a pointer to ints
int const **ptr       // a pointer to a pointer to constant int value
                      // (not a pointer to a constant pointer to ints)
int *const *ptr       // a pointer to a const pointer to int values
                      // (not a constant pointer to a pointer to ints)
int **const ptr       // a constant pointer to pointers to ints
                      // (ptr, the identifier, being const makes no sense)
int const **const ptr // a constant pointer to pointers to constant int values

İşaretçi tanımlarıyla ilgili son bir not: her zaman mümkün olduğunca sağa işaretçi simgesini (*) yazın. İşaretçi sembolünü türe eklemek zor bir iştir, çünkü durum böyle değil, bir işaretçi türünü kuvvetle önerir. İşte bazı örnekler:

int* a;          /* write: */     int *a;    // a is a pointer to an int
int* a, b;       // CONFUSING 
                 /* write: */     int *a, b; // a is a pointer to an int, 
                 //                             but b is a mere int
int* a, *b;      // UGLY: both a and b are pointers to ints
                 /* write: */     int *a, *b;

Bjarne Stroustrup'un SSS'si, bu sorunu önlemek için C ++ kuralı kullanılıyorsa, satır başına yalnızca bir değişken bildirilmesini önerir.

Aynı hususlar, referansları ve rvalue referanslarını tanımlamak için de geçerlidir:

int var = 22;
int const &refToConst = var;         // OK
int const& ref2 = var, ref3 = var;   // CONFUSING:
                                     // ref2 is a reference, but ref3 isn't:
                                     // ref3 is a constant int initialized with
                                     // var's value
int &const constRef = var;           // ERROR: as references can't change anyway.

// C++:
int&& rref = int(5), value = 10;     // CONFUSING:
                                     // rref is an rvalue reference, but value is
                                     // a mere int. 
                                     /* write: */ int &&rref = int(5), value = 10;

İşaretçilere çok boyutlu diziler ve başvurular (veya işaretçiler) kullanıldığında daha karmaşık bildirimlerle karşılaşılır. Bazen bu tür bildirimlerin kafa karıştırıcı ve hataya açık olduğu ve bu nedenle kaçınılması veya daha üst düzey yapılarla değiştirilmeleri gerektiği iddia edilse de, bu bölümün başında açıklanan prosedür her zaman belirsizlikler veya kafa karışıklığı olmadan kullanılabilir.

Parametreler ve değişkenler

const hem fonksiyon parametreleri hem de değişkenler ( statik veya otomatik, genel veya yerel dahil) üzerinde bildirilebilir. Yorum, kullanımlar arasında değişir. Bir const statik bir değişken (genel değişken ya da statik yerel değişken) bir sabittir ve bu gibi matematiksel sabitler gibi veri için kullanılabilir double const PI = 3.14159 - gerçekçi artık, ya da genel derleme parametreleri. Bir const otomatik bir değişken (statik olmayan yerel değişken) olup aracı tek bir atama farklı bir değer gibi, her zaman kullanılabilir olsa da, oluyor int const x_squared = x * x . const Referansla geçirme içindeki bir parametre, başvurulan değerin değiştirilmediği ( sözleşmenin bir parçası olduğu) anlamına gelirken, değerle geçirilen bir const parametre (veya referansla geçerken işaretçinin kendisinin) hiçbir şey eklemediği anlamına gelir arabirime (değer kopyalandıkça), ancak dahili olarak işlevin parametrenin yerel kopyasını değiştirmediğini belirtir (bu tek bir atamadır). Bu nedenle, bazıları const yalnızca sözleşmeyi değiştirdiği referansa göre parametrelerin kullanılmasını tercih eder, ancak uygulamayı açığa çıkardığı değerle geçiş için değil.

C ++

Yöntemler

Yararlanmak amacıyla sözleşme ile tasarım gibi yöntemleri yanı sıra üye veri olabilir kullanıcı tanımlı tipler (struct'lar ve sınıflar) için yaklaşımla, programcı örnek yöntemleri etiket olabilir const onlar nesnenin veri üyeleri değiştirebilir yoksa. Uygulama const örneği yöntemlerine eleme dolayısıyla const-doğruluğu için gerekli bir özelliktir ve diğer birçok kullanılamaz nesne yönelimli gibi dillerde Java ve C # veya Microsoft 'ın C ++ / CLI veya C ++ için Yönetilen Uzantılar . İken const yöntemler tarafından çağrılabilir const ve sivil const hem nesneler, olmayan const yöntemleri yalnızca olmayan devreye sokulabilen const nesneler. const Bir örnek yöntemi ile modifiye edici "ile gösterilen bir nesneye uygulanır this tüm örnek yöntemlere iletilen örtülü bir argümandır" işaretçi. Dolayısıyla const yöntemlere sahip olmak, this diğer argümanlar gibi " " örtük işaretçi argümanına sabit doğruluğu uygulamanın bir yoludur .

Bu örnek şunları göstermektedir:

class C
{
    int i;
public:
    int Get() const // Note the "const" tag
      { return i; }
    void Set(int j) // Note the lack of "const"
      { i = j; }
};

void Foo(C& nonConstC, C const& constC)
{
    int y = nonConstC.Get(); // Ok
    int x = constC.Get();    // Ok: Get() is const

    nonConstC.Set(10); // Ok: nonConstC is modifiable
    constC.Set(10);    // Error! Set() is a non-const method and constC is a const-qualified object
}

Yukarıdaki kodda, örtük " this " gösterici Set() " C *const " tipine sahiptir ; diğer yandan, " this " Get() türü olan işaretçi " C const *const ", yöntemin nesnesini " this " gösterici aracılığıyla değiştiremeyeceğini belirtir .

Genellikle programcı hem bir tedarik edecek const ve olmayan bir const arayan her iki tip karşılamak için bir sınıftaki aynı adlı (fakat muhtemelen çok farklı kullanımlar) yöntemi ile. Düşünmek:

class MyArray
{
    int data[100];
public:
    int &       Get(int i)       { return data[i]; }
    int const & Get(int i) const { return data[i]; }
};

void Foo( MyArray & array, MyArray const & constArray )
{
    // Get a reference to an array element
    // and modify its referenced value.

    array.Get( 5 )      = 42; // OK! (Calls: int & MyArray::Get(int))
    constArray.Get( 5 ) = 42; // Error! (Calls: int const & MyArray::Get(int) const)
}

const Çağrı nesnesinin -lık belirler versiyonu MyArray::Get() çağrılır ve böylece arayan o işlemek ya da yalnızca nesne özel veri gözlemlemek hangi bir referans verilir olsun ya da olmasın. İki yöntemin teknik olarak farklı imzaları vardır çünkü onların this işaretçileri " " farklı tiplere sahiptir ve derleyicinin doğru olanı seçmesine izin verir. ( Yalnızca değere göre döndürmek yerine bir const başvuruyu int döndürmek, int ikinci yöntemde aşırı olabilir, ancak aynı teknik, Standart Şablon Kitaplığı'nda olduğu gibi rastgele türler için de kullanılabilir .)

Sabit doğruluk için boşluklar

C ve C ++ 'da saf sabit doğruluğu için birkaç boşluk vardır. Öncelikle mevcut kodla uyumluluk için varlar.

Yalnızca C ++ için geçerli olan birincisi, const_cast programcının const niteleyiciyi kaldırmasına ve herhangi bir nesneyi değiştirilebilir hale getirmesine izin veren kullanımıdır . Niteleyicinin çıkarılması gerekliliği, değiştirilemeyen ancak sabit doğru olmayan mevcut kod ve kitaplıkları kullanırken ortaya çıkar. Örneğin, şu kodu göz önünde bulundurun:

// Prototype for a function which we cannot change but which
// we know does not modify the pointee passed in.
void LibraryFunc(int* ptr, int size);

void CallLibraryFunc(int const * ptr, int size)
{
    LibraryFunc(ptr, size); // Error! Drops const qualifier

    int* nonConstPtr = const_cast<int*>(ptr); // Strip qualifier
    LibraryFunc(nonConstPtr, size);  // OK
}

Bununla birlikte, kendisi const bir const dönüştürme yoluyla bildirilen bir nesneyi değiştirme girişimi , ISO C ++ Standardına göre tanımsız davranışa neden olur. Yukarıdaki örnekte, ptr olarak bildirilen bir global, yerel veya üye değişkene const veya öbek üzerinden tahsis edilen bir nesneye atıfta bulunuyorsa new int const , kod yalnızca LibraryFunc işaret edilen değeri gerçekten değiştirmezse doğrudur ptr .

C dilinin bir boşluk ihtiyacı vardır çünkü belirli bir durum mevcuttur. Statik depolama süresi olan değişkenlerin bir başlangıç ​​değeriyle tanımlanmasına izin verilir. Bununla birlikte, başlatıcı yalnızca dize sabitleri ve diğer değişmez değerler gibi sabitleri kullanabilir ve başlatıcı öğeleri bildirilmiş olsun const ya da olmasın, ya da statik süre değişkeninin bildirilip bildirilmediği değişken adları gibi sabit olmayan öğeleri kullanmasına izin verilmez const . const Statik depolama süresi olan bir değişkeni başlatmanın taşınabilir olmayan bir yolu vardır. Daha sonraki bir atamanın sol tarafında dikkatli bir şekilde bir typecast oluşturarak, bir const değişken, const niteliği etkili bir şekilde sıyırıp diğer const değişkenler ve benzeri gibi sabit olmayan öğelerle 'başlatarak' yazılabilir . Bir const değişkene bu şekilde yazmak amaçlandığı gibi işe yarayabilir, ancak tanımlanmamış davranışlara neden olur ve sabit doğrulukla ciddi şekilde çelişir:

size_t const    bufferSize = 8*1024;
size_t const    userTextBufferSize;  //initial value depends on const bufferSize, can't be initialized here

...

int setupUserTextBox(textBox_t *defaultTextBoxType, rect_t *defaultTextBoxLocation)
{
    *(size_t*)&userTextBufferSize = bufferSize - sizeof(struct textBoxControls);  // warning: might work, but not guaranteed by C
    ...
}

Başka bir boşluk hem C hem de C ++ için geçerlidir. Spesifik olarak, diller, üye işaretçilerinin ve referanslarının const sahiplerinin -oluşuna göre "yüzeysel" olduğunu, yani üye puanları (ve hakemler) haricinde const tüm const üyeleri içeren kapsayıcı bir nesne olduğunu belirtir. Göstermek için şu C ++ kodunu göz önünde bulundurun:

struct S
{
    int val;
    int *ptr;
};

void Foo(S const & s)
{
    int i  = 42;
    s.val  = i;  // Error: s is const, so val is a const int
    s.ptr  = &i; // Error: s is const, so ptr is a const pointer to int
    *s.ptr = i;  // OK: the data pointed to by ptr is always mutable,
                 //     even though this is sometimes not desirable
}

Nesne rağmen s geçirilen Foo() üyelerinin sabiti hepsi yapar sabit olduğunu pointee erişilebilir yoluyla s.ptr bu açısından istenir olmayabilir rağmen hala değiştirilebilir olduğunu const çünkü -correctness s kudretinin yalnızca pointee kendi. Bu nedenle Meyers, üye işaretçileri ve referansları için varsayılanın "derinlik" olması gerektiğini const savunur; bu mutable , pointee konteynere ait olmadığında bir niteleyici tarafından geçersiz kılınabilir , ancak bu strateji mevcut kodla uyumluluk sorunları yaratır. Bu nedenle, tarihsel nedenlerden dolayı, bu boşluk C ve C ++ 'da açık kalır.

İkinci boşluk, işaretçiyi const -doğru bir arabirimin arkasına gizlemek için bir sınıf kullanılarak kapatılabilir , ancak bu tür sınıflar ya bir const nesneden olağan kopyalama anlamlarını desteklemez (içeren sınıfın da olağan anlambilim tarafından kopyalanamayacağı anlamına gelir) veya const kasıtsız veya kasıtlı kopyalama yoluyla -hoşluğun kaldırılmasına izin vererek diğer boşluklara izin vermek .

Son olarak, C standart kitaplığındaki çeşitli işlevler, const bir karakter dizgisine bir gösterici kabul ettikleri const ve aynı dizenin bir parçasına işaretçi olmayan bir döndürdükleri için , sabit-doğruluğunu ihlal eder . strtol ve strchr bu işlevler arasındadır. C ++ standart kitaplığının bazı uygulamaları, örneğin Microsoft'un bazı işlevlerin aşırı yüklenmiş iki sürümünü sağlayarak bu boşluğu kapatmaya çalışır: bir " const " sürüm ve bir "olmayan const " sürüm.

Problemler

Sabitliği ifade etmek için tip sisteminin kullanılması çeşitli karmaşıklıklara ve sorunlara yol açar ve buna göre eleştirilmiştir ve C ve C ++ 'dan büyük ölçüde etkilenen dar C ailesi C, C ++ ve D dışında benimsenmemiştir. Java ve C #, her ikisi de açıkça reddedilen const -style tür niteleyicileri, bunun yerine tanımlayıcıya uygulanan anahtar sözcüklerle ( final Java'da const ve readonly C #'de) sabitliği ifade eder . C ve C ++ içinde bile const , bazı projeler ve kuruluşlar onu tutarlı bir şekilde kullanırken, diğerleri bundan kaçınırken , kullanımı önemli ölçüde değişir.

strchr sorun

const Bir fonksiyonu mantığı, giriş sabittir ya da değil, fakat döner bir girişi ile aynı nitelikli tür olmalıdır bir değer olup agnostik olduğunda zorluklar çıkarmaktadır niteleyici türü. Diğer bir deyişle, bu işlevler için, girdi sabitse (sabit nitelikli), dönüş değeri de olmalıdır, ancak girdi değişkense ( const niteliksiz), dönüş değeri de olmalıdır. Çünkü tür imzası bir form - bu fonksiyonlar farklılık nedeniyle, aynı mantıkla (çoklu giriş durumunda potansiyel olarak daha fazla ya da) iki işlevleri gerektiren genel programlama .

Bu sorun, özellikle C standart kitaplığındaki basit işlevler için bile ortaya çıkar strchr ; bu gözlem, Ritchie tarafından 1980'lerin ortalarında Tom Plum'a aktarıldı. strchr İşlevi, bir dizede bir karakter bulur; biçimsel olarak, karakterin c dizedeki ilk oluşumuna bir işaretçi döndürür s ve klasik C'de (K&R C) prototipi:

char *strchr(char *s, int c);

strchr İşlevi giriş dizesi değiştirmez, ancak dönüş değeri genellikle gibi değerini değiştirecek bir arayan tarafından kullanılır:

if (p = strchr(q, '/'))
    *p = ' ';

Bu nedenle, bir taraftan giriş dizesi olabilir olabilir const (bu fonksiyon ile değiştirilmez, çünkü) ve giriş dize ise const dönüş değeri de olmalıdır - en basit ilk karakter eğer tam giriş işaretçiyi geri çünkü bir eşleşmedir - ancak diğer yandan , arayan kişi orijinal dizeyi değiştirmek için işaretçiyi kullanmak isteyebileceğinden const , orijinal dizge değilse dönüş değeri olmamalıdır const .

C ++ 'da bu , tipik olarak bir şablon aracılığıyla uygulanan ve iki işlevle sonuçlanan işlev aşırı yükleme yoluyla yapılır , böylece dönüş değeri girdi ile aynı nitelikte türe sahiptir : const

char* strchr(char* s, int c);
char const* strchr(char const* s, int c);

Bunlar sırayla bir şablonla tanımlanabilir:

template <T>
T* strchr(T* s, int c) { ... }

D'de bu, inout const, immutable veya unqualified (değişken) için bir joker karakter görevi gören anahtar kelime aracılığıyla ele alınır ve sonuçta:

inout(char)* strchr(inout(char)* s, int c);

Bununla birlikte, C'de bunların hiçbiri mümkün değildir, çünkü C fonksiyon aşırı yüklemesine sahip değildir ve bunun yerine, girdinin sabit olduğu ancak çıktının yazılabilir olduğu tek bir fonksiyona sahip olarak bu işlenir:

char *strchr(char const *s, int c);

Bu, deyimsel C koduna izin verir, ancak girdi gerçekte sabit nitelikliyse, tür güvenliğini ihlal ederek const niteleyicisini kaldırır. Bu çözüm, Ritchie tarafından önerilmiş ve daha sonra benimsenmiştir. Bu fark, C ve C ++ uyumluluğunun başarısızlıklarından biridir .

D

D programlama dilinin 2. Sürümünde , const ile ilgili iki anahtar sözcük bulunmaktadır. immutable Anahtar herhangi bir referans yoluyla değiştirilemez verileri temsil eder. const Kelime kesilebilir veri olmayan bir değişken bir görünüm gösterir. C ++ 'dan farklı olarak const , D const ve immutable "derin" veya geçişlidir ve bir const veya immutable nesne aracılığıyla erişilebilen her şey const veya immutable sırasıyla.

D'de sabit ve değişmezlik örneği

int[] foo = new int[5];  // foo is mutable.
const int[] bar = foo;   // bar is a const view of mutable data.
immutable int[] baz = foo;  // Error:  all views of immutable data must be immutable.

immutable int[] nums = new immutable(int)[5];  // No mutable reference to nums may be created.
const int[] constNums = nums;  // Works.  immutable is implicitly convertible to const.
int[] mutableNums = nums;  // Error:  Cannot create a mutable view of immutable data.

D'de geçişli veya derin sabit örneği

class Foo {
    Foo next;
    int num;
}

immutable Foo foo = new immutable(Foo);
foo.next.num = 5;  // Won't compile.  foo.next is of type immutable(Foo).
                   // foo.next.num is of type immutable(int).

Tarih

const tarafından tanıtılan Bjarne Stroustrup içinde sınıfları ile C için önceki C ++ 1981 yılında, ve ilk olarak adlandırıldı readonly . Stroustrup motivasyona gelince:

"İki işleve hizmet etti: kapsam ve tür kurallarına uyan (yani bir makro kullanmadan) sembolik bir sabiti tanımlamanın bir yolu olarak ve bellekteki bir nesneyi değişmez saymanın bir yolu olarak."

Makrolara alternatif olarak kapsamlı ve türlenmiş bir alternatif olarak ilk kullanım, inline anahtar kelime aracılığıyla işlev benzeri makrolar için benzer şekilde yerine getirildi . Sabit işaretçiler ve * const gösterim, Dennis Ritchie tarafından önerildi ve bu nedenle benimsendi.

const daha sonra standardizasyonun bir parçası olarak C'de benimsenmiştir ve C89'da (ve sonraki sürümlerde) diğer tür niteleyiciyle birlikte görünür volatile . noalias X3J11 komitesinin Aralık 1987 toplantısında başka bir niteleyici önerildi, ancak reddedildi; nihai restrict olarak C99'daki anahtar kelime ile amacına ulaşıldı . Ritchie, "ağırlıklarını taşımadıklarını" savunarak, bu eklemeleri pek desteklemedi, ancak sonuçta standarttan çıkarılmalarını tartışmadı.

D daha sonra const bir tür oluşturucu ( tür niteleyicisi değil ) olarak bilinen ve iki ek tür oluşturucu ekledi immutable ve inout ilgili kullanım durumlarını işlemek için C ++ 'dan miras alındı .

Diğer diller

Diğer diller, genellikle yüzeysel olarak benzer yapılara sahip olsalar ve const anahtar kelimeyi kullanabildikleri halde, türün sabitlik kısmına sahip olmalarında C / C ++ 'ı takip etmezler . Genellikle bu yalnızca sabitler (sabit nesneler) için kullanılır.

C # bir const anahtar kelimeye sahiptir, ancak kökten farklı ve daha basit anlambilimle: derleme zamanı sabiti anlamına gelir ve türün bir parçası değildir.

Nim , const C # anahtar kelimesine benzer bir anahtar sözcüğe sahiptir : türün bir parçasını oluşturmaktan ziyade bir derleme zamanı sabiti de bildirir. Bununla birlikte, Nim'de, derleme zamanında değerlendirilebilen herhangi bir ifadeden bir sabit bildirilebilir. C # 'da, yalnızca C # yerleşik türleri şu şekilde bildirilebilir const ; sınıflar, yapılar ve diziler dahil olmak üzere kullanıcı tanımlı türler olamaz const .

Java'da yoktur const - bunun yerine final yerel "değişken" bildirimlerine uygulanabilen ve türe değil tanımlayıcıya uygulanabilen vardır . Adın kökeni olan nesne üyeleri için farklı bir nesne yönelimli kullanımı vardır.

Java dil belirtimi, const ayrılmış bir anahtar sözcük olarak kabul edilir - yani değişken tanımlayıcı olarak kullanılamayan bir anahtar kelime - ancak ona anlamsallık atamaz: ayrılmış bir sözcüktür (tanımlayıcılarda kullanılamaz), ancak bir anahtar sözcük değildir (özel bir anlamı). Anahtar kelime rezervasyonunun, Java dilinin bir uzantısının C ++ tarzı const yöntemler ve yazıya işaretçi içermesine izin vermek için gerçekleştiği düşünülmektedir const . Java Topluluk Sürecinde , const doğruluğu uygulamaya yönelik bir geliştirme talebi bileti mevcuttur , ancak geriye doğru uyumlu bir şekilde uygulanmasının imkansız olduğu gerekçesiyle 2005 yılında kapatılmıştır.

Çağdaş Ada 83 bağımsız olarak sabit bir nesne ve bir constant anahtar kelime kavramına sahipti, giriş parametreleri ve döngü parametreleri örtük olarak sabitti. Burada, constant türün değil, nesnenin bir özelliğidir.

JavaScript , yeniden atanamayan veya yeniden const bildirilemeyen blok kapsamlı bir değişkeni tanımlayan bir bildirime sahiptir . Yeniden tanımlanamayan bir değişkene salt okunur bir referansı tanımlar, ancak bazı durumlarda değişkenin değeri potansiyel olarak değişebilir, örneğin değişken bir nesneye atıfta bulunuyorsa ve onun bir özelliği değiştirilmişse.

Ayrıca bakınız

Notlar

Referanslar

Dış bağlantılar