Soru Üstbilgideki işlev parametreleri olarak kullanılan “ilkel” türlerin önündeki “const” öğesinin kaldırılması daha mı iyi?


Kod gözden geçirme işleminde, iş arkadaşlarımdan biri, üstbilgide bir işlev parametresi olarak kullanılan "ilkel türler" in önündeki "const" öğelerinin anlamsız olduğunu ve bu "const" leri kaldırmayı önerdiğini söyledi. Bu tür durumlarda yalnızca kaynak dosyada "const" kullanılmasını önerdi. İlkel tipler "int", "char", "float" vb.

Aşağıdaki örnek.

example.h

int ProcessScore(const int score);

example.cc

int ProcessScore(const int score) {
  // Do some calculation using score
  return some_value;
}

Onun önerisi şöyle yapıyor:

example.h

int ProcessScore(int score);  // const is removed here.

example.cc

int ProcessScore(const int score) {
  // Do some calculation using score
  return some_value;
}

Ama biraz kafam karıştı. Genellikle, kullanıcı yalnızca başlığa bakar, bu nedenle başlık ve kaynak dosya arasında tutarsızlık varsa, karışıklığa neden olabilir.

Bu konuda biraz tavsiyede bulunabilir mi?


44
2017-09-19 05:30


Menşei


@PasserBy - Gerçekten değil. - StoryTeller
@PasserBy Herhangi bir const yerel değişkenini bildirmekle aynı şekilde her zaman işe yaramaz. - juanchopanza
@PasserBy "Değişken" 'i değiştirmek, herhangi bir "değişken"' i değiştirmek gibi, işlevin uygulanmasında sorunlara neden olabilir. Uygulamaya, argüman sadece bir başka yereldir. - juanchopanza
const Derleyici, parametrenin değiştirilmesinin amaçlanmadığı bir sinyaldir. Kod değiştirmeyi denerse, bu yöntem / işlevin amacına aykırı olduğu için bir uyarı (veya hata) yükseltilir. - Steve
@Steve Aklıma daha da önemlisi, const başka bir sinyaldir Programcılar parametrenin değiştirilmesinin amaçlanmadığı. Bu, derleyicinin onunla anlamlı bir şey yapabildiği veya yapmayabileceği gerçeği çok daha önemlidir. Öncelikle diğer kişilerin okuyabileceği ve derleyicinin ayrıştırması için tesadüfen kod yazması, bakımı daha az can sıkıcı hale getirir. - Dan Mills


Cevaplar:


İçin herşey türleri (sadece ilkel değil) Üst düzey işlev bildirgesindeki const niteleyicileri yoksayılır. Yani aşağıdaki dört, aynı işlevi bildirir:

void foo(int const i, int const j);
void foo(int i, int const j);
void foo(int const i, int j);
void foo(int i, int j);

Const niteleyici işlev içinde yok sayılmaz. vücut, ancak. Orada const doğruluğu üzerinde etkisi olabilir. Ama bu fonksiyonun bir uygulama detayıdır. Yani genel fikir birliği:

  1. Konsolu bildirimden çıkar. Bu sadece dağınıklık ve istemcilerin işlevi nasıl arayacağını etkilemez.

  2. Const bırakın tanımında Derleyicinin parametrenin yanlışlıkla değiştirilmesini yakalamak için isterseniz.


65
2017-09-19 05:47



@snb Bunun oldukça büyük bir anlaşma olduğunu iddia ediyorum. Eğer bir rastlasaydım const by-value argümanı, geliştiricinin bir hata yaptığını veya C ++ 'da deneyimsiz olduğunu varsaymak isterim. Argümanlar için const Sadece girdilerin mutabilitesini kontrol ettikleri için referanslar ya da işaretçiler için düzenleyiciler olduklarında anlam ifade eder. Değere göre geçirilen türler için eklenecek gerçek anlamsal bir anlam sağlamaz. const ona. Düzenle: Bunu eklemeliyim, ancak argüman kabul etmeyi seçtiniz, sadece tutarlı ol. Tutarlılık okunabilirlik için önemlidir; aksi takdirde const argümanlar özel bir anlamı varmış gibi görünebilir. - Bitwize
@Bitwize Nasıl bir argüman bu "oldukça büyük bir anlaşma". Bireylerin kodlama yetenekleri hakkındaki varsayımlarınız oldukça ilgisiz IMO'dur. En iyi ides, const değer kalifikasyonunun gerçekten önemli olduğu, aynı zamanda kaynak imzanızdan da işlev şablonları oluşturabilir, bu yüzden imzanın değiştirilmesi gerçekten herhangi bir fayda için oldukça can sıkıcı gibi görünür. Sadece son zamanlarda Clion gibi şeyler bile bunu kontrol etti (geçen ay gibi) - opa
@snb Tartışmaya çalışmıyorum, sadece fikrimi bildiriyordum. Ve constUygulamadaki nitelikler, hâlâ yazınsal türlerde büyük bir farklılık yaratmamaktadır. Edebi türler olduklarından, kimsenin kopyalama değeri ve kopyayı değiştirmek. Değerler referans veya işaretçi tarafından aktarılmadığından (ve böylece geçerli dizinin dışından herhangi bir şey değiştirilmediğinden), constargümanın gerçekliği, bir geliştiricinin gerçek tip argümanlarla ne yapabildiğini değiştirmez. - Bitwize
@snb - Bu hiç de kritik değil. Beyanname ve tanım eşleşmesi gereken bir sıralama olmadıkça. Yani eğer sen başlansan const Her yerde, istemciler API'nizi kullanırlar ve sonra fikrinizi değiştirirsiniz ... Yapı sistemi yeniden oluşturulacak her şey Mermiyi ısırmaz ve başlığını değiştirmezseniz, hiçbir sebep olmadan. Bu yüzden, başlangıç ​​bildirgesinde bir kurucu olmayabilir. - StoryTeller
@underscore_d Takip ediyorum const-correctness; lütfen orijinal mesajımı yanlış anlamayın. Kötü kod yazmayı savunmuyorum. Kesinlikle başvuruyorum const bir ortak API'daki by-value argümanları. API'da dekorasyon yaparken, yardım et Tüketicinin hiç bir anlamı yoktur. Tüketicinin iç / uygulama geliştirme uygulamalarını bilmesi gerekmemelidir. Uygulamada olduğu gibi: neyin uygun olduğuna dair çeşitli görüşler var. const- doğruluk - sizinki gibi, kesinlikle her şey, hatta argümanlar, başlangıç const; ve bu geçerli bir yaklaşım. - Bitwize


Aşırı yük çözünürlüğüne geldiğinde const olarak adlandırılan ve const olmadan işlev parametresi aynıdır. Yani örneğin işlevler

void f(int);
void f(const int);

aynıdır ve birlikte tanımlanamaz. Sonuç olarak, olası kopyalardan kaçınmak için tüm parametreler için bildirimde const kullanmamak daha iyidir. (Const constifier veya const pointer hakkında konuşmuyorum - const düzenleyici üst düzey değil.)

İşte standarttan kesin alıntı.

Listeyi oluşturduktan sonra   Parametre türlerinin, bir parametre türünü değiştiren herhangi bir üst düzey cv-niteleyicileri, oluştururken silinir   işlev türü. Elde edilen transforme edilmiş parametre türleri ve elipsin varlığı veya yokluğu   veya bir işlev parametre paketi, işlevin parametre türü listesidir. [Not: Bu dönüşüm değil   parametrelerin türlerini etkiler. Örneğin, int(*)(const int p, decltype(p)*) ve int(*)(int, const int*) aynı türlerdir. - not notu]

Fonksiyon tanımındaki kurgunun faydası tartışmalıdır - bunun ardındaki akıl yürütme aynıdır yerel değişkeni bildirmek için const kullanma - Diğer programcılara kodun okunması, bu değerin işlev içinde değiştirilmeyeceğini gösterir.


40
2017-09-19 05:42



Bu, işaretçi adresleri için de geçerlidir (işaretçi değerleri değil). kullanım const char * kamu bildirimlerinizde ve const char * const uygulamanızda. - Nicholas Shanks
Görünüşe göre " herşey aşırı yüklenme çözünürlüğüne gelirken, const olarak bildirilen ve const içermeyen parametreler aynıdır. "Aslında, dil söz konusu olduğunda, aynı imza; aşırı yüklenme çözünürlüğü onu ayırmaz: Aynı programda tanımlanan üst seviye param sıkılığından sadece iki farklı fonksiyona sahip olamazsınız. Bunun nedeni, C / C ++ içindeki tüm parametrelerin (işaretçiler dahil) değer olarak geçirilmesidir, böylece hiçbir işlev onları değiştiremez. Bunu anlamak önemlidir const char * hak eder hedefişaretçi değil. - Peter A. Schneider
Örneğin TU struct S {}; void f(const S s){} void f(S s) {} keyfi olarak karmaşık S - Peter A. Schneider
İlk paragrafınız ve teklifiniz birbiriyle çelişiyor gibi görünüyor. - Rakete1111
@ Rakete1111 Ne şekilde? - Artemy Vysotsky


Kod incelemesinde verilen tavsiyelere uyun.

kullanma const Değer argümanlarının semantik değeri yoktur - fonksiyonunuzun uygulanması için sadece anlamlı (potansiyel olarak) - ve bu durumda bile gereksiz olduğunu iddia ederim.

Düzenle: Sadece açık olmak gerekirse: işlevinizin prototipi genel arayüz senin fonksiyonuna Ne const referansları değiştirmeyeceğinizi garanti eder.

int a = 7;
do_something( a );

void do_something(       int& x );  // 'a' may be modified
void do_something( const int& x );  // I will not modify 'a'
void do_something(       int  x );  // no one cares what happens to x

kullanma const TMI'ya benzer bir şeydir - 'x' değiştirilmiş olsun ya da olmasın, işlevin dışında hiçbir yerde önemli değildir.

edit2: Ayrıca bilgileri de çok beğeniyorum StoryTeller’ın cevabı


15
2017-09-19 05:43





Diğer birçok kişi, API perspektifinden yanıtladığı gibi, hepsi de eşdeğerdir ve aşırı yüklenme için eşittir:

void foo( int );
void foo( const int );

Ama daha iyi bir soru, bunun sağlanıp sağlanmadığıdır. herhangi bir anlamsal anlam bu API’nın bir tüketicisine ya da herhangi bir geliştirici Uygulamanın

Bunu açıkça tanımlayan iyi tanımlanmış bir geliştirici kodlama yönergeleri olmadan, const Skaler argümanların açıkça belirgin semantik anlamı yoktur.

Bir tüketiciden: const int girişinizi değiştirmez. Hala bir literal olabilir veya başka bir değişkenden olabilir (her ikisi de const veya olmayanconst)

Bir geliştiriciden: const int bir kısıtlama getiriyor yerel kopya değişkenin (bu durumda, bir işlev argümanı). Bu sadece argümanı değiştirmek anlamına gelir, değişkenin başka bir kopyasını alır ve bunun yerine değiştirirsiniz.

Bir argüman by-value değerini kabul eden bir işlevi çağırırken, çağrılan işlev için yığında bu argümanın bir kopyası yapılır. Bu işlev, tüm kapsamı için, daha sonra değiştirilebilen, hesaplamalar için kullanılan vb. - çağrıya iletilen orijinal girişi etkilemeden argümanın yerel bir kopyasını verir. Etkin olarak, bu, girdisinin yerel değişken argümanını sağlar.

Argümanı constBu sadece bu kopyanın değiştirilemeyeceği anlamına gelir; ama öyle değil Geliştiricinin kopyalamasını ve bu kopyada değişiklik yapmasını yasaklar. Bu, başlangıçtan beri bir kopya olduğu için, uygulamanın içinden çok fazla zorlamıyor - ve sonuçta tüketicinin bakış açısından çok fark yaratmıyor.

Bu tam tersi referans ile geçmek, burada bir referans int& semantik olarak farklıdır const int&. İlk, girişini mutasyona sokabilir; ikincisi sadece girdiyi gözlemleyebilmektedir ( const_cast  const-uzaklık - ama bu olasılığı görmezden gelelim); Böylece, constReferanslardaki anlam, anlamsal anlam taşır.

Kamu API'sında çok fayda sağlamaz; ve (imo) uygulamada gereksiz kısıtlamalar getirmektedir. Rasgele, mahrem bir örnek olarak - basit bir işlev gibi:

void do_n_times( int n )
{
   while( n-- > 0 ) {
       // do something n times
   } 
}

şimdi gereksiz bir kopya kullanılarak yazılmalıdır:

void do_n_times( const int n )
{
    auto n_copy = n;
    while( n_copy-- > 0 ) {
        // do something n times
    }
}

Ne olursa olsun const Kamu API'sında skaler kullanılır, bir anahtar şey olmaktır tutarlı tasarım ile. API kullanımı arasında rastgele değişirse const skaler argümanlar kullanmakconst Skaler, daha sonra tüketiciye ima edilen anlamın var olup olmadığı konusunda kafa karışıklığına neden olabilir.

TL; DR:  const Genel bir API'daki skaler türler, alan adınız için kendi yönergeleriniz tarafından açıkça tanımlanmadıkça anlamsal bir anlam taşımamaktadır.


7
2017-09-19 21:03





ben düşünce o const derleyici için bazı ifadelerin değişmediği ve buna göre optimize etmenin bir ipucudur. Mesela sayının kareköküne kadar bölenleri arayarak bir sayının asal olup olmadığını test ediyordum ve argümanı açıkladığını düşündüm. const alırdı sqrt(n) dışında for Döngü, ama yapmadı.

Başlıkta gerekli olmayabilir, ama sonra tekrar ihtiyacın tek şey argümanı değiştirmemek ve asla gerekli olmadığını söyleyebilirsin. Görmeyi tercih ederim const sadece kaynakta değil, aynı zamanda başlıkta da bulunur. Beyanname ve tanım arasındaki tutarsızlıklar beni ihtiyatlı kılar. Sadece benim düşüncem.


-2
2017-09-19 18:53



const olmanın bir işlevi ile ilgisi yok "saf" işlevi (yan etki yok, sonuç sadece girdiye bağlıdır). Derleyiciniz kaldırılamıyorsa (int)sqrt((double)n)) dışında i < (int)sqrt((double)n)) döngü durumu, optimizasyon seviyesini açmayı deneyin. Umarım yazmıyordun i < sqrt(n)çünkü bu bir double karşılaştırması. - Peter Cordes
Görmek stackoverflow.com/questions/2798188/... ve stackoverflow.com/questions/28405492/.... - Peter Cordes
@peter Muhtemelen uyarıdan kurtulmak için doğru şekilde yapıyordum, doublekarşılaştırma, bu yüzden baş yukarı için teşekkürler :) Neyse, ne dedim const soru kapsamı dışında, demek istediğim eğer const kodu okuyan kimseye bir miktar açıklama getiriyor, derleyici tarafından istenmese bile bırakılmalı; Sonuçta, girinti de gerekli değil, ama bu iyi bir uygulama. - Lio
Hala insanların anlayabileceğini söylüyorsun double foobar(const double) demek istedim foobar Saf bir işlevdir ve aynı argümanla tekrarlanan çağrılar (el ile) en iyi duruma getirilebilir. Ama bu değil Çoğu insan bunu nasıl yorumlayacaktır, çünkü bu bağlamda anlamı bu değildir. Aradığın şey double foobar(double) PURE;PURE'in hala insanlar için anlamı olan boş bir makro olabileceği ya da bunu destekleyen derleyicilerde olduğu gibi __attribute__((const)). - Peter Cordes
Oh, sanırım ne dediğini anladım. Demek istediğini ilan ediyordun const nkendi fonksiyonunuzun tanımında? Derleyicileri optimize etmek, değişkenler kendi başlarına değişmediğinde zaten anlamaya çalışır. Diğer yorumcular veya cevaplar (unuttuğum) const içinde tanım genellikle iyi değildir ve bir değişkeni değiştirilmemiş olarak tutmak istediğinizde hatalardan kaçınabilirsiniz, ör. sizi const olmayan referans ile iletmekten vazgeçerek. (C ++ gibi kesinlikle yararlıdır mutate(int &x) C.) 'da yok - Peter Cordes