Имеет ли смысл когда-либо использовать фундаментальный (не указатель) параметр const?

Thanx много приятель, ваш код работал для меня.

Вот код:

$soap_do = curl_init(); 
curl_setopt($soap_do, CURLOPT_URL,            $url );   
curl_setopt($soap_do, CURLOPT_CONNECTTIMEOUT, 10); 
curl_setopt($soap_do, CURLOPT_TIMEOUT,        10); 
curl_setopt($soap_do, CURLOPT_RETURNTRANSFER, true );
curl_setopt($soap_do, CURLOPT_SSL_VERIFYPEER, false);  
curl_setopt($soap_do, CURLOPT_SSL_VERIFYHOST, false); 
curl_setopt($soap_do, CURLOPT_POST,           true ); 
curl_setopt($soap_do, CURLOPT_POSTFIELDS,    $post_string); 
curl_setopt($soap_do, CURLOPT_HTTPHEADER,     array('Content-Type: text/xml; charset=utf-8', 'Content-Length: '.strlen($post_string) )); 
curl_setopt($soap_do, CURLOPT_USERPWD, $user . ":" . $password);

$result = curl_exec($soap_do);
$err = curl_error($soap_do);  
13
задан Scott Smith 16 March 2010 в 05:36
поделиться

5 ответов

Помните шаблон if (NULL == p) ?

Многие люди скажут «вы должен писать такой код: "

if(NULL == myPointer) { /* etc. */ }

вместо

if(myPointer == NULL) { /* etc. */ }

. Причина в том, что первая версия защитит кодировщик от опечаток кода, таких как замена" == "на" = "(потому что запрещается присваивать значение переменной постоянное значение).

Следующее можно считать расширением этого ограниченного шаблона if (NULL == p) :

Почему константные параметры могут быть полезны для кодировщика

Независимо от типа , «const» - это квалификатор, который я добавляю, чтобы сообщить компилятору, что « Я не ожидаю, что значение изменится, поэтому отправьте мне сообщение об ошибке компилятора, если я солгу ».

Например, такой код покажет, когда компилятор может мне помочь:

void bar_const(const int & param) ;
void bar_non_const(int & param) ;

void foo(const int param)
{
   const int value = getValue() ;

   if(param == 25) { /* Etc. */ } // Ok
   if(value == 25) { /* Etc. */ } // Ok

   if(param = 25) { /* Etc. */ } // COMPILE ERROR
   if(value = 25) { /* Etc. */ } // COMPILE ERROR

   bar_const(param) ;  // Ok
   bar_const(value) ;  // Ok

   bar_non_const(param) ;  // COMPILE ERROR
   bar_non_const(value) ;  // COMPILE ERROR

   // Here, I expect to continue to use "param" and "value" with
   // their original values, so having some random code or error
   // change it would be a runtime error...
}

В тех случаях, которые могут произойти либо из-за опечатки в коде, либо из-за ошибки в вызове функции, компилятор перехватит хорошая вещь .

Почему это не важно для пользователя

Бывает, что:

void foo(const int param) ;

и:

void foo(int param) ;

имеют одинаковую подпись.

Это хорошо, потому что, если разработчик функции решает, что параметр считается константным внутри функции, пользователь не должен и не должен это знать.

Это объясняет, почему мои объявления функций для пользователей опускают const:

void bar(int param, const char * p) ;

, чтобы объявление было как можно более ясным, в то время как мое определение функции добавляет его в максимально возможной степени:

void bar(const int param, const char * const p)
{
   // etc.
}

, чтобы сделать мой код как можно более надежным .

Почему в реальном мире он мог сломать

Но меня укусил мой шаблон.

На каком-то неработающем компиляторе, который останется анонимным (имя которого начинается с « Sol » и заканчивается на « aris CC »), две указанные выше подписи могут рассматриваться как разные ( в зависимости от контекста), и, таким образом, ссылка времени выполнения , возможно, выйдет из строя.

Поскольку проект компилировался также на платформах Unix (Linux и Solaris), на этих платформах неопределенные символы оставались разрешенными при выполнении, что вызывало ошибку времени выполнения в середине выполнения процесса.

Итак, поскольку мне пришлось поддерживать упомянутый компилятор, я прекратил загрязнять даже свои заголовки составными прототипами.

Но я все же считаю этот шаблон добавления const в определение функции хорошим.

Примечание: у Sun Microsystems даже хватило смелости скрыть свое сломанное искажение с помощью объявления « в любом случае это зло, поэтому вы не должны использовать его ». см. http://docs.oracle.com/cd/E19059-01/stud.9/817-6698/Ch1.Intro.html#71468

Последнее примечание

Следует отметить, что Бьярн Страуструп, похоже, был против того, чтобы рассматривать void foo (int) как тот же прототип, что и void foo (const int) :

На мой взгляд, не все принятые функции являются улучшением , хотя. Например, [...] правило, согласно которому void f (T) и void f (const T) обозначают одну и ту же функцию (предложено Томом Plum из соображений совместимости с C) [имеют] сомнительное различие наличия проголосовали за C ++ «над моим мертвым телом».

Источник: Бьярн Страуструп
Развитие языка в реальном мире и для него: C ++ 1991-2006 , 5. Особенности языка: 1991–1998 , стр.21.
http://www.stroustrup.com/hopl-almost-final.pdf

Забавно, что Херб Саттер предлагает противоположную точку зрения:

Рекомендация: Избегайте передачи const-by-value параметры в объявлениях функций. По-прежнему сделайте параметр const в определении той же функции, если он не будет изменен.

Источник: Herb Sutter
Exceptional C ++ , Пункт 43: Const-Correctness , p177-178.

27
ответ дан 1 December 2019 в 06:39
поделиться

Это заставляет компилятор выполнять часть работы по отлову ваших ошибок. Если вы не должны его изменять, сделайте его const, а если забудете, компилятор на вас накричит.

4
ответ дан 1 December 2019 в 06:39
поделиться

Если bar помечен const, как указано выше, то человек, читающий код, зная, что было передано, всегда знает точно, что содержит bar. Нет необходимости предварительно просматривать код, чтобы узнать, не изменилось ли значение bar в какой-либо точке пути. Это делает рассуждения о коде более простыми и тем самым уменьшает возможность появления ошибок.

Я сам голосую за "хорошую практику". Конечно, в настоящее время я также являюсь приверженцем функциональных языков, так что....


Обращаясь к комментарию ниже, рассмотрим этот исходный файл:

// test.c++

bool testSomething()
{
    return true;
}

int test1(int a)
{
    if (testSomething())
    {
        a += 5;
    }
    return a;
}

int test2(const int a)
{
    if (testSomething())
    {
        a += 5;
    }
    return a;
}

В test1 у меня нет способа узнать, каким будет возвращаемое значение, не прочитав (потенциально большое и/или запутанное) тело функции и, не отследив (потенциально далекое, большое, запутанное и/или недоступное) тело функции testSomething. Кроме того, изменение a может быть результатом ужасной опечатки.

Та же опечатка в test2 приводит к следующему результату во время компиляции:

$ g++ test.c++
test.c++: In function ‘int test2(int)’:
test.c++:21: error: assignment of read-only parameter ‘a’

Если это была опечатка, то она была поймана для меня. Если это не опечатка, то следующий вариант кодирования, IMO, лучше:

int test2(const int a)
{
    int b = a;
    if (testSomething())
    {
        b += 5;
    }
    return b;
}

Даже полудохлый оптимизатор сгенерирует идентичный код, как в случае test1, но вы сигнализируете, что нужно быть внимательным и осторожным.

Написание кода для удобочитаемости включает в себя гораздо больше, чем просто выбор красивых имен.

3
ответ дан 1 December 2019 в 06:39
поделиться

Это обсуждалось много раз, и в большинстве случаев людям приходилось соглашаться, чтобы не соглашаться. Лично я согласен с тем, что это бессмысленно, и стандарт неявно соглашается - квалификатор const (или volatile) верхнего уровня не является частью сигнатуры функции. На мой взгляд, желание использовать подобный квалификатор верхнего уровня указывает (строго), что человек может на словах отделять интерфейс от реализации, но на самом деле не понимает различия.

Еще одна небольшая деталь: это применимо к ссылкам так же хорошо, как и к указателям ...

7
ответ дан 1 December 2019 в 06:39
поделиться

Я склонен быть немного извергом const , так что лично мне это нравится. В основном полезно указать читателю кода, что переданная переменная не будет изменена; точно так же, как я пытаюсь пометить каждую другую переменную, которую я создаю в теле функции, как const , если она не изменена.

Я также стараюсь поддерживать соответствие сигнатур функций, даже если в этом нет особого смысла. Отчасти потому, что он не причиняет никакого вреда, а отчасти потому, что Doxygen немного запутался, если подписи были разными.

3
ответ дан 1 December 2019 в 06:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: