Жоғарғы деңгейдегі const функция қолтаңбасына әсер етпейді

C ++ Primer 5-ші басылымынан ол былай дейді:

int f(int){ /* can write to parameter */}
int f(const int){ /* cannot write to parameter */}

Екі функция айырмашылығы жоқ . Бірақ сіздер білетіндей, екі функция өз параметрлерін қалай жаңарта алатындығымен ерекшеленеді.

Біреу маған түсіндіре ала ма?


EDIT
I think I didn't interpret my question well. What I really care is why C++ doesn't allow these two functions simultaneously as different function since they are really different as to "whether parameter can be written or not". Intuitively, it should be!


EDIT
The nature of pass by value is actually pass by coping argument values to parameter values. Even for references and pointers where thee copied values are addresses. From the caller's viewpoint, whether const or non-const is passed to the function does not influence values (and of course types of) copied to parameters.
The distinction between top-level const and low-level const matters when copying objects. More specifically, top-level const(not the case of low-level const) is ignored when copying objects since copying won't influence the copied object. It is immaterial whether the object copied to or copied from is const or not.
So for the caller, differentiating them is not necessary. Likely, from the function viewpoint, the top-level const parameters doesn't influence the interface and/or the functionality of function. The two function actually accomplish the same thing. Why bother implementing two copies?

8
Егер сіз сілтемелер немесе сілтемелер туралы айтқан болсаңыз, бұл өзгеше болады
қосылды автор Cogwheel, көзі
Олар қоңырау шалушы үшін айырмашылығы жоқ. Өздерінің көшірмелерін өзгерткеніне қамқорлық жасау керек емес.
қосылды автор chris, көзі
қосылды автор doctorlove, көзі
Егер сіз « & » қоспасаңыз, онда const - бұл дәлелдер көшіріледі. Басқа жағдайда int f (int /) және int f (const int /) айырмашылығы бар және пайдалы болады.
қосылды автор WiSaGaN, көзі
Дегенмен, сіздің жергілікті стиль ережелеріңіз функцияның функционалдық параметрлерінің мәнін, яғни «const int» дегенді өзгертуге болмайды.
қосылды автор MikeW, көзі
@WiSaGaN Thx. Тағы бір ұқсас оқиға - көрсеткіш *.
қосылды автор Zachary, көзі

7 жауаптар

осы екі функцияны әртүрлі функция ретінде бір мезгілде рұқсат етіңіз, себебі олар «параметрлерді жазуға бола ма, жоқ па» дегенді білдіреді. Интуитивті, бұл керек!

Функцияларды шамадан тыс жүктеу шалушы қамтамасыз ететін параметрлерге негізделген. Бұл жерде қоңырау шалушы const немесе const мәнін бере алады, бірақ логикалық түрде бұл функцияның функциясына ешқандай айырмашылық болмауы керек. Мысалы:

f(3);
int x = 1 + 2;
f(x);

Егер f() осы жағдайлардың әрқайсысында әртүрлі болса, онда бұл өте шатасуы мүмкін! f() деп аталған осы кодының бағдарламашы бағдарламаны жарамсыз параметрлерді жіберетін айнымалы мәндерді еркін шығарып немесе шығарып тастайды. Бұл қауіпсіз, ақылға қонымды мінез-құлық, сізден ерекше жағдайларды ақтауды қалайтын нүкте болып табылады және функцияның шамадан тыс жүктелуі кезінде әртүрлі can мінез-құлықтары бар:

void f(const int&) { ... }
void f(int&) { ... }

Мәселен, менің ойымша, сіз интуитивті емес деп ойлаймын: C ++ сілтемелерден әлдеқайда сілтеме үшін C ++ көп «қауіпсіздікті» қамтамасыз етеді.

Мен ойлайтын себептер:

  • So when a programmer knows a non-const& parameter will have a longer lifetime, they can select an optimal implementation. For example, in the code below it may be faster to return a reference to a T member within F, but if F is a temporary (which it might be if the compiler matches const F&) then a by-value return is needed. This is still pretty dangerous as the caller has to be aware that the returned reference is only valid as long as the parameter's around.
    T f(const F&);
    T& f(F&);   //return type could be by const& if more appropriate
  • const секілді біліктіліктердің таралуы:
    const T& f(const F&);
    T& f(F&);

const немесе const түрінде көрсетілетін кейбір (ықтимал F member-) T f() деп аталатын параметрдің const - параметріне негізделген. Интерфейстің мұндай түрі сыныпты мүше емес функцияларымен кеңейтуді қаласаңыз (сыныптың минимализмін сақтау үшін немесе шаблондарды/альгостарды көптеген класстарда қолдануға болады), бірақ идея const const жолында рұқсат етілмеген v [0] = 3 vector :: operator []() сияқты мүше функциялары бірақ const бір емес.

Мәндер мән бойынша қабылданған кезде, олар функция қайтарылатындықтан, ауқымнан шығып кетеді, сондықтан параметрлердің бір бөлігіне сілтеме қайтару және оның біліктіліктерін тарқатқысы келетін дұрыс сценарий жоқ.

Қалаған әрекетті бұзу

Сілтемелерге қатысты ережелерді ескере отырып, оларды сіз өзіңіз қалаған мінез-құлық түрін алу үшін пайдалана аласыз - тек қана конструктивті емес параметрді кездейсоқ түрде өзгертпеуге мұқият болыңыз, сондықтан төмендегілерге ұқсас тәжірибені қабылдағыңыз келуі мүмкін const параметрлері:

T f(F& x_ref)
{
    F x = x_ref; //or const F is you won't modify it
    ...use x for safety...
}

Рекомбинации салдары

const - негізделген параметрдің мәніне негізделген тілді жүктеуге тыйым салатын мәселеден басқа, const код> - мәлімдемесінде және анықтамасында.

f (const int) / f (int) үшін ... егер сіз тақырыпты файлда функцияны жарияласаңыз, онда const біліктілігі, тіпті кейінірек анықтамасы іске асыру файлында болады. Өйткені, күтіп ұстау кезінде бағдарламашы іріктеуішті жоюды қалауы мүмкін ... оны тақырыптан алып тастау клиенттік кодты нашар рекомпиляциялауға әкелуі мүмкін, сондықтан оларды синхрондауда талап етпейтін жақсы, сондықтан, Егер олар әртүрлі болса қате жібереді. Егер сіз функцияны анықтауға тек const қоссаңыз немесе алып тастасаңыз, онда ол функцияның әрекетін талдау кезінде кодтың оқырмандары констсит туралы қамқорлық жасауы мүмкін жерде жүзеге асыруға жақын. Егер сізде тақырып const болса, онда бағдарламашы оны const емес етеді және клиентті болдырмау үшін тақырыпты жаңартуды ұмытпайды немесе шешпейді рекомпиляция, ол басқа жолмен салыстырғанда қауіпті, себебі бағдарлама жұмыс істейтін мінез-құлық туралы дұрыс емес түсіндірулерге әкеліп соқтыратын қолданыстағы енгізу кодын талдауға тырысқанда, бағдарламашының үстінен const нұсқасын есте сақтайды. Бұл барлық өте нашар қолдау көрсету мәселесі - тек коммерциялық бағдарламалауға шынымен сәйкес келеді, бірақ бұл интерфейсте const қолданылмайтын нұсқаулықтың негізі. Сонымен қатар, интерфейсінен шығып, клиенттің бағдарламашыларына сіздің API-іңізді оқып білу әлдеқайда жақсы.

8
қосылды
@Zack: нүкте, тақырыпқа кез-келген өзгеріс рекомпиляцияны іске қосады, сондықтан егер сіз іске асыруды еркін өзгертуді өзгерткіңіз келсе, тақырып кейде анықтамамен синхрондалмайды деп ұйғаруға тура келеді. Егер сіз мұны қабылдайтын болсаңыз, үстіңгі деректемеге қарағанда әлдеқайда ыңғайлы нәрсе айтуға болады, себебі бағдарламашының дұрыс емес деп санайтыны дұрыс, себебі оның қауіпсіздігі/const және кодтың мінез-құлқына қатысты қате пікір білдіруі мүмкін. Сондай-ақ, клиенттің кодерлеріне ұнайтын тақырыптағы қысқаша ақпараттар бар - олар const ма екенін неге айтып бермейді?
қосылды автор Tony Delroy, көзі
@Zack: f (9 + 4) немесе f (g ()) int g (); компилятор параметрді уақытша деп қарастырады, сондықтан f (int &) функциясын қолданбайды, бірақ const сілтемесін уақытша f (const int /) жоғарыдағы қоңырауларды қабылдай алады.
қосылды автор Tony Delroy, көзі
@Zack, сіз қолданатын тақырып файлында орындалмаса, клиентті қайта байланыстыруыңыз қажет.
қосылды автор juanchopanza, көзі
Мен ханчопанза алдым. Әсіресе сіз кітапхананы іске асырғыңыз келеді. Бұл бөліну жинағы деп аталады.
қосылды автор Zachary, көзі
Клиентті қайта құрусыз іске асыруға const қалай қосуға/жоюға болады? Сценарийді елестете алмаймын. Сіз көмектесе аласыз?
қосылды автор Zachary, көзі
тақырыпты жою оны клиенттің кодын дұрыс емес қайта жинауға әкелуі мүмкін . Неліктен тақырып файлында ЖОҚ const клиенттің кодын қайта құрастыруға қажет емес?
қосылды автор Zachary, көзі
C ++ жүйесінде. Тек констант сілтемесі уақытша нысанмен байланыстырылуы мүмкін. Рақмет.
қосылды автор Zachary, көзі
ол const деп есептелетін уақытша болып табылатын мән негізінде құндылығы бойынша толықтай өңделуі мүмкін Қосымша мәліметтер бере аласыз ба?
қосылды автор Zachary, көзі

Қоңырау шалушы үшін ешқандай айырмашылық болмағандықтан және жоғарғы деңгейдегі const параметрімен функцияға қоңырауды ажырата алмайтын нақты әдіс болмағандықтан, тіл ережелері жоғарғы деңгейдегі констілерді елемейді. Бұл дегеніміз, бұл екі

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

сол декларация ретінде қарастырылады. Егер сіз екі іске асыруды қамтамасыз етсеңіз, сіз бірнеше анықтаманың қатесін аласыз.

Жоғары деңгейдегі const функциясымен анықтау функциясында айырмашылық бар. Біреуінде параметрдің көшірмесін өзгертуге болады. Екінші жағынан, мүмкін емес. Оны іске асыру мәліметі ретінде көре аласыз. Қоңырау шалушыға ешқандай айырмашылық жоқ.

// declarations
void foo(int);
void bar(int);

// definitions
void foo(int n)
{
  n++;
  std::cout << n << std::endl;
}

void bar(const int n)
{
  n++;//ERROR!
  std::cout << n << std::endl;
}

Бұл төмендегілерге ұқсас:

void foo()
{
  int = 42;
  n++;
  std::cout << n << std::endl;
}

void bar()
{
  const int n = 42;
  n++;//ERROR!
  std::cout << n << std::endl;
}
4
қосылды
@TonyD Бұл (а) C-ден екі үйлесімділікті бұзатын C-дан түбегейлі өзгеріс және қолданыстағы кодтың 100% -ы (b) пайдалы мақсатқа қызмет етпейді. Маңызды емес сияқты.
қосылды автор n.m., көзі
Кез-келген функцияны foo (5) деп атауға болады. Егер екеуі де бар болса, оны қалай шешуге болады?
қосылды автор n.m., көзі
@ juanchopanza: құрметпен, мені ескі C ++ хакерлердің түйсігі бұл жылдар бойы заңсыз екенін біліп, бұрмаланған деп ойлаймын. Бір тривиальдық күш мүмкіндігі: foo (const int) немесе foo (int) арасында таңдау керек сияқты foo (const int) > және foo (int &) . Қалай болғанда да, менің ойымша, бұл қауіпті және пайдалы емес (жауапқа сай) пайдалы емес, оны жүзеге асыру немесе интуитивті емес деп санаймын.
қосылды автор Tony Delroy, көзі
@ n.m. (а) дұрыс емес ... функцияның шамадан тыс жүктелуіне жол берген ереже ғана болуы мүмкін - бұл қазіргі уақытта заңсыз болып табылады - сондықтан қолданыстағы кодекске әсер етпейді (b) бұл мәселе осы мәселе бойынша сұранысқа ие емес, const және non-const сілтемелері үшін заңды жүктеумен салыстырғанда ;-)
қосылды автор Tony Delroy, көзі
foo (const int) деп аталады және foo (my_var) foo (5) foo int) . Компилятордың бұл оркестрді жасай алатыны қиялдан тыс емес, қызықты мәселе - оның тілі оны қолдамайды.
қосылды автор Tony Delroy, көзі
@Zack Бұл тек тілдік ереже. Жоғарғы деңгейдегі констент қоңырау шалушы үшін ешқандай айырмашылық жоқ деп есептеледі, сондықтан оны декларацияда елемейді. Осылайша, ешқашан шатастырмау үшін функционалдық декларацияларыңызда ешқашан жоғарғы деңгейдегі констисттерді орналастырмаңыз.
қосылды автор juanchopanza, көзі
@TonyD Менің болжауымша, бір сәтте интуитивті мінез-құлықтың болмағандықтан (жоғарғы деңгейдегі конститтерді емдеу үшін) ережелердің тұтас жиынтығын ойлап табудың қажеті жоқ деп шешілді (мен foo 5) foo (const int) параметрін қалау үшін , мен ережені оқып шығу керек еді, неге ол мұны қалай таңдады?).
қосылды автор juanchopanza, көзі
@TonyD Әрине, мен тек қана ойландырған едім, және сіз көптеген жылдардан кейін қолданыстағы ережелер интуитивті бола бастаған дұрыссыз. Кейінірек «дизайн мен эволюцияны» қарастырамын. Мен сенің де жауапыңды дауыс беремін!
қосылды автор juanchopanza, көзі
Мен сіздің ұғымыңызды білемін. Бірақ неге C ++ екі функцияның бірдей функцияның атына (қоңырау шалушының аспектісінен) рұқсат бермейді. Интуитивті, бұл болуы керек!
қосылды автор Zachary, көзі

«C ++ бағдарламалау тілі», төртінші басылымында, Бжарн Струффп (§12.1.3):

Өкінішке орай, С үйлесімділігін сақтау үшін const ең жоғары деңгейде аргумент түрінде еленбейді. Мысалы, бұл бірдей функцияның екі мәлімдемесі:

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

Мәселен, басқа жауаптардың біріне қарсы, C ++-ның бұл ережесі екі функцияның немесе басқа да осындай ұтымдылықтардың айырмашылығы себебінен таңдалмаған, бірақ оның орнына кем дегенде оңтайлы шешім ретінде таңдалмаған сияқты. сыйысымдылық.

Шынында да, D бағдарламалау тілінде осы екі шамадан артық жүктеу болуы мүмкін. Дегенмен, бұл сұраққа басқа жауаптардың қайшы келуі мүмкін, егер функция литералымен шақырылса, constst жүктемесі артықшылық береді:

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

f(42);//calls void f(int);

Әрине, сіз жүктемелеріңізге эквиваленттік семантиканы қамтамасыз етуіңіз керек, бірақ бұл шамадан тыс жүктеу функциясымен ерекшеленетін бұл жүктеме сценарийіне тән емес.

2
қосылды

Түсініктемелер айтылғандай, бірінші функцияның ішіндегі параметр, егер ол аталса, өзгертілуі мүмкін. Бұл callee's int көшірмесі. Екінші функцияның ішінде, callee's int-ның көшірмесі болып табылатын параметрге енгізілген кез келген өзгерістер компиляция қатесіне әкеледі. Const - айнымалы мәнді өзгертпейтін уәде.

1
қосылды

Функция қоңырау шалушы тарапынан ғана пайдалы.

Қоңырау шалушы үшін ешқандай айырмашылық болмағандықтан, бұл екі функция үшін айырмашылық жоқ.

1
қосылды

Сұрағыңыздың бұл бөлігіне жауап беріңіз:

C ++ бұл екі функцияны бір мезгілде әртүрлі функция ретінде пайдалануға мүмкіндік бермейді, себебі олар «параметрлерді жазуға бола ма, жоқ па» дегенді білдіреді. Интуитивті, бұл керек!

Егер сіз бұл туралы біраз ойлайсыз, онда интуитивті емес - шын мәнінде, ол мағынасы жоқ. Әрқайсысының айтқаны бойынша, қоңырау шалушы функцияның параметрін мән бойынша қабылдайтындай әсер етпейді және ол да көңілге келмейді.

Енді бір сәтте шамадан тыс жүктеу рұқсаты const деңгейінде жұмыс істегенін де қарастырайық. Осындай екі мәлімдеме

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

екі түрлі функцияларды жариялайды. Мәселелердің біреуі осы сөйлемшені шақыратын функциялар: foo (42) . Тіл ережелері литералдардың констент екенін және бұл жағдайда «шамадан тыс жүктеу» деп аталуы мүмкін. Бірақ бұл ең аз мәселе. Бағдарламашы жеткілікті зұлымдықты сезінуі мүмкін:

int foo(const int i) { return i*i; }
int foo(int i)       { return i*2; }

Енді сіз екі шамадан тыс жүктемелерге ие бола аласыз, семантикалық түрде қоңырау шалушыға теңестіріледі, бірақ мүлдем басқа нәрселерді жасайды. Енді бұл жаман болады. Біз пайдаланушыларды ұсынатын нәрселерге емес, оларды жасайтын жолмен шектейтін интерфейстерді жаза аламыз.

0
қосылды
@Zack Erm жақсы, мен білемін. Параметр типтері (және const біліктілігі жоғарғы деңгейде болмағанда, мысалы, const int & vs int & ) өзгереді. Егер сіз тілге екі түрлі функциялардың декларациясы ретінде int foo (const int) және int foo (int) емдеуін қаласаңыз, жоғарғы деңгей const болар еді (қажет болса, жанама) қолтаңбаның бір бөлігі. Мен сіздердің шатасуларыңыздың қайдан пайда болғанына және жауап берушілерден не естігіңіз келетініне сенімді емеспін.
қосылды автор jrok, көзі
@Zack TonyD неге соншалықты жақсы түсіндіреді. Бірақ егер тіл жұмыс істеген болса, сіз оны ойласаңыз, содан кейін иеленетін деген атауды қолтаңбаның бөлігі ретінде секілді тақырыптарда қолдануға болады.
қосылды автор jrok, көзі
Дұрыс, қоңырау шалушы ештеңеге қарамайды. Содан кейін, клиент кодын тікелей әсер етпейтін іске асыру бөлшектерімен неге шектелуге болады?
қосылды автор jrok, көзі
қосылды автор Zachary, көзі
Сіздің идеяларым бар. Мен тек жоғары деңгейлі типтегі іріктеуіштерді ғана күтемін. Төменгі деңгейлер үшін бұл өзгеше.
қосылды автор Zachary, көзі
const - бұл тек іріктеуіш. Ол функцияның қолтаңбасын қамтымайды.
қосылды автор Zachary, көзі
@Tony D'ның жауабына жүгініңіз. Клиенттік код тек тақырып файлын қамтуы керек. Әдетте, тақырып файлында NO const функциясының декларациясында қолданылады.
қосылды автор Zachary, көзі
Бұл шын мәнінде интуитивті емес, өйткені жоғары деңгейлі конструктор функциясы құндылық деп аталады. Мәселен, қоңырау шалушының көзқарасы бойынша, оған ешқандай көңіл бөлінбейді.
қосылды автор Zachary, көзі

Менің ойымша, айырмашылығы жоқ шамадан тыс жүктеу және компилятор жағдайында пайдаланылады, оларды қоңырау шалушы арқылы бөлуге болады.

Компилятор осы екі функцияның арасындағы айырмашылықтарды көрсетпейді, олардың атаулары бірдей қиылысады. Бұл компилятор осы екі декларацияны қайта анықтау ретінде қарастыратын жағдайға әкеледі.

0
қосылды