Что означает const в конце функции c
Как пользоваться const в C++?
Введение
Реклама
Переменные и const
Наиболее простой и интуитивно понятный вариант использования const заключается в объявлении константных значений:
Похожего результата можно добиться с помощью макросов:
Но вариант с макросом не столь хорош, поскольку не дает возможности указать тип переменной. Из-за возможных проблем с типизацией лучше пользоваться константами, а не макросами. Более того, макросов лучше и вовсе избегать. В C++ реализована прекрасная поддержка шаблонных функций и классов, которые в большинстве случаев представляют более надежную альтернативу. Однако стоит признать, что бывают случаи, когда макросы оказываются полезными. Но сейчас речь не о них.
А что, если мы по какой-то причине не может пользоваться C++11? И в этом случае можно легко объявить константный вектор:
То есть для сложных типов, которые не получается заполнить в одну строку, достаточно вынести компоновку в отдельную функцию для инициализации. С другой стороны, мы могли бы объявить вектор в функции makeVector() с ключевым словом static и вместо константы использовать саму функцию. Но это уже дело вкуса:
Константная ссылка объявляется схожим образом:
Суть константных ссылок заключается в том, что мы получаем доступ к значению переменной, на которую сделана ссылка, но изменить ее не имеем права. Основное назначение константных ссылок заключается в передаче входных параметров функциям. Но об этом немного позже.
Для указателей существует три варианта использования const :
В варианте 1 мы получили указатель, который можно использовать как более гибкую константную ссылку. Он работает почти так же, но мы можем в любой момент сослаться на другую переменную. Вариант 2 работает так же, как обычная ссылка. Значение менять можно, а указать на другую переменную не выйдет. И наконец вариант 3. Он равносилен случаю константной ссылки. То есть один раз объявили указатель и ничего больше менять не можем.
В первом и втором варианте вполне можно обойтись использованием ссылок. Особой разницы нет. Для третьего ограничиться ссылкой получится не всегда. Например:
Строку в стиле C с помощью ссылки мы объявить не сможем. Нужен указатель. И он должен быть константным, поскольку изменение содержания строки запрещено и приведет к неопределенному поведению. А второй const здесь не помешает, чтобы получить жесткую привязку указателя к заданному значению и запретить случайные присвоения:
Реклама
Функции и const
Если же вы хотите передать в функцию объект структуры или класс, то используйте константную ссылку:
Каноничным примером на этот случай является конструктор копирования:
Если бы мы попытались передать в конструктор копирования не ссылку, а значение, то для инициализации этого значения нам пришлось бы вызвать конструктор копирования, который мы и хотим реализовать.
Еще const можно использовать для объявления константных функций-членов классов:
Но тут есть один тонкий момент. Иногда бывает полезно инкапсулировать информацию о том, что на самом деле внутреннее состояние класса меняется, но все равно объявить функцию-член константной. Например, в многопоточной среде мы можем использовать мьютексы:
Заключение
const (C++)
При изменении объявления данных const ключевое слово указывает, что объект или переменная не являются изменяемыми.
Синтаксис
Значения-константы
const Ключевое слово указывает, что значение переменной является константой и сообщает компилятору о том, что программист не сможет его изменить.
В C++ const вместо директивы препроцессора const можно использовать ключевое слово, чтобы определить постоянные значения. Значения, определенные с помощью, const подчиняются проверке типа и могут использоваться вместо константных выражений. В C++ можно указать размер массива с помощью const переменной следующим образом:
В языке C константные значения по умолчанию имеют внешнюю компоновку, поэтому они могут использоваться только в файлах исходного кода. В языке C++ константные значения по умолчанию имеют внутреннюю компоновку, которая позволяет использовать их в файлах заголовков.
const Ключевое слово также можно использовать в объявлениях указателей.
Указатели на данные-константы можно использовать в качестве параметров функций, чтобы функция не могла изменять параметр, переданный посредством указателя.
Для объектов, не объявленных как константы, можно вызывать как константные, так и неконстантные функции-члены. Можно также перегружать функцию-член с помощью const ключевого слова; это позволяет вызывать другую версию функции для постоянных и неконстантных объектов.
Нельзя объявлять конструкторы или деструкторы с const ключевым словом.
Функции-члены-константы
Объявление функции-члена с помощью const ключевого слова указывает, что функция является функцией «только для чтения», которая не изменяет объект, для которого она вызывается. Функция-член константы не может изменять какие-либо нестатические элементы данных или вызывать функции-члены, не являющиеся константами. Чтобы объявить функцию-член константы, поместите const ключевое слово после закрывающей скобки списка аргументов. const Ключевое слово требуется как в объявлении, так и в определении.
Различия констант C и C++
При объявлении переменной, как const в файле исходного кода на языке C, это можно сделать следующим образом:
Затем эту переменную можно использовать в другом модуле следующим образом:
Но чтобы получить такое же поведение в C++, необходимо объявить const переменную как:
Если вы хотите объявить extern переменную в файле исходного кода C++ для использования в файле исходного кода на языке C, используйте:
для предотвращения изменения имени компилятором C++.
Remarks
При использовании списка параметров функции-члена const ключевое слово указывает, что функция не изменяет объект, для которого она вызывается.
Дополнительные сведения о const см. в следующих разделах:
Многоликий const
Ключевое слово const — одно из самых многозначных в C++. Правильно использование const позволяет организовать множество проверок ещё на этапе компиляции и избежать многих ошибок из числа тех, которые бывает трудно найти при помощи отладчиков и/или анализа кода.
Первая половина заметки рассчитана скорее на начинающих (надеюсь мнемоническое правило поможет вам запомнить, где и для чего используется const), но, возможно, и опытные программисты смогут почерпнуть интересную информацию о перегрузке методов по const.
Константы и данные
Самый простой случай — константные данные. Возможно несколько вариантов записи:
Все они правильные и делают одно и тоже — создают переменную, значение которой изменить нельзя.
Константы и указатели
При использовании const с указателями, действие модификатора может распространяться либо на значение указателя, либо на данные на которые указывает указатель.
Работает (const относится к данным):
Тоже самое и тоже работает:
А вот это уже не работает:
Если бы операция присвоения изменяла бы не указатель, а данные:
то ситуация была бы диаметрально противоположной.
Существует мнемоническое правило, позволяющее легко запомнить, к чему относится const. Надо провести черту через «*», если const слева, то оно относится к значению данных; если справа — к значению указателя.
Ну и конечно, const можно написать дважды:
Константы и аргументы/результаты функций
C функциями слово const используется по тем же правилам, что при описании обычных данных.
Константы и методы (перегрузка)
А вот с методами есть одна тонкость.
Во-первых, для методов допустимо использование const, применительно к this. Синтаксис таков:
Кроме того, этот const позволяет перегружать методы. Таким образом, вы можете писать оптимизированные варианты методов для константных объектов.
То есть для константного объекта (с x=2) был вызван соответствующий метод.
Осталось только добавить, что если вы планируете использовать const-объекты, то вам надо обязательно реализовать const-методы. Если вы в этом случае не реализуете не-const-методы, то во всех случаях будут молча использоваться const-методы. Одним словом, const лучше использовать там, где это возможно.
И ещё… я собрался в отпуск… возможно, не смогу ответить на комментарии до понедельника-вторника. Не сочтите за невнимание 🙂
Так вы думаете, что знаете Const?
Думаете, что вы знаете все правила использования const для С? Подумайте еще раз.
Основы const
Скалярные переменные
Вы знакомы с простым правилом const в С.
const перед hello означает, что во время компиляции происходит проверка того, что hello никогда не меняется.
Кроме того, C не сильно беспокоится о том, где расположен const до тех пор пока он находится перед идентификатором, так что объявления const uint32_t и uint32_t const идентичны:
Скалярные переменные в прототипах
Сравните прототип и реализацию следующей функции:
Однако, ваш компилятор будет жаловаться на несоответствие const для параметров, являющихся указателями или массивами, так как в таком случае ваша функция будет иметь возможность манипулировать данными на которые ссылается передаваемый указатель.
Массивы
Вы можете указать const для всего массива.
const также может указываться после объявления типа:
Структуры
Обычные структуры
Вы можете указать const для всей структуры.
Если мы попытаемся изменить какой-либо член someStructA :
const внутри структуры
Вы можете указать const для отдельных членов структуры:
Если мы попытаемся изменить какие-либо члены someOtherStructB :
Указатели
const для указателей — вот где начинается веселье.
Один const
Давайте использовать указатель на целое число в качестве примера.
Два const
Давайте добавим ещё один const и посмотрим как пойдут дела.
Ага, у нас получилось сделать и данные, и сам указатель неизменяемыми.
Интерлюдия — объясняем объявления const
Но подождите, дальше — больше!
Это распространенный шаблон для перебора последовательностей данных: переходить к следующему элементу, увеличивая указатель, но не позволяя указателю изменять данные.
Допустимое значение указателя это всегда скалярный адрес памяти ( uintptr_t ), поэтому здесь const оказывает тот же эффект, как и в случае с обычными целочисленными значениями, т.е. совершенно нормально, если ваша реализация использует const для определения параметров, но прототип вашей функции не обязан включать их, так как этот const защищает только адрес, но не данные.
Три const
Сколько способов мы можем использовать, чтобы добавить const к двойному указателю?
Давайте быстро это проверим.
Какие из этих операций допускаются, исходя из объявления выше?
Только первое присваивание не сработало, потому что, если мы прочитаем наше объявление справа налево:
Что, если мы хотим добавить еще один модификатор const на уровень глубже?
Теперь мы дважды защищены от изменений, потому что, если мы прочитаем наше объявление справа налево:
Что если мы хотим заблокировать все изменения при объявлении двойного указателя?
Что теперь мы (не)можем сделать?
Ничего не работает! Успех!
Дополнительные правила
Хаки приведения типов
Что если вы умны и создали изменяемый указатель на неизменяемое хранилище?
Поскольку это C, вы можете отбросить квалификатор const явным преобразованием типа и избавиться от предупреждения (а также нарушения инициализации const ):
Хаки памяти
Что если структура содержит const члены, но вы измените хранящиеся в ней данные после объявления?
Давайте объявим две структуры, различающиеся только константностью их членов.
Будет ли это работать?
Неа, это не работает, потому что прототип 6 для memcpy выглядит так:
memcpy не позволяет передавать ей неизменяемые указатели в качестве dst аргумента, так как dst изменяется при копировании (а someStructA неизменяема).
Заключение
Не создавайте изменяемых значений без необходимости. Будьте внимательны к тому, чтобы ваша программа на самом деле работала так, как вы планировали.
C++ поддерживает две нотации неизменности:
constexpr функция должна быть достаточно простой, чтобы вычисляться компилятором, а также возвращать вычисленное значение. constexpr функции могут вызываться неконстантыми аргументами в контексте которых не требуются константные выражения.
const
Объекты со спецификатором const не могут быть изменены, а также должны быть инициализированы.
Поскольку объекты со спецификаторов const не могут быть изменены, то следующий код будет ошибочным:
Обратите внимание, что const изменяет тип объекта, а не указание того, как должна быть назначена переменная. const ограничивает способы работы с объектом.
При использовании указателя задействуются два объекта: сам указатель и объект, на который указывает. Префиксное’ объявление указателя с const делает константным объект, а не указатель. Чтобы объявить как const сам указатель, а не объект, на который он указывает, необходимо поместить const после символа указателя. Например:
Местоположение const относительно базового типа не принципиально, поскольку не существует типа данных const*. Принципиальным является положение const относительно символа *. Поэтому возможны следующие записи:
Первая версия используется для строк, элементы которых не должны быть изменены функцией и возвращает указатель на const, который не позволяет изменять результат. Вторая версия используется для изменяемых строк.
Вы можете назначить адрес неконстантной переменной указателю на константу, потому что это не может нанести никакого вреда. Однако адрес константы нельзя назначить неконстантному указателю, поскольку это позволит изменить значение объекта. Например:
constexpr
Константное выражение является выражением, которое вычисляется во время компиляции. Константные выражения не могут использовать значения и переменные, которые не известны во время компиляции.
Существует множество причин, по которым кому-то может понадобиться именованная константа, а не буква или значение, хранящееся в переменной:
Значение constexpr вычисляется во время выполнения компиляции, и если оно не может быть вычислено, то компилятор выдаст ошибку.