Какая польза от константных указателей (в отличие от указателей на константные объекты)?

Я часто использовал указатели для создания объектов, например...

const int *p;

Это просто означает, что вы не можете изменить целое число, которое p указывает на сквозной p, Но я также видел ссылку на константные указатели, объявленные так...

int* const p;

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

Какое возможное использование это будет иметь?

11 ответов

Решение

Когда вы разрабатываете программы на C для встроенных систем или программы специального назначения, которые должны ссылаться на одну и ту же память (многопроцессорные приложения, совместно использующие память), вам нужны постоянные указатели.

Например, у меня есть 32-битный процессор MIP с небольшим ЖК-дисплеем. Я должен записать свои данные LCD на определенный порт в памяти, который затем отправляется на контроллер LCD.

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

Кроме того, мне может потребоваться, чтобы он был энергозависимым, что также может быть приведено, но проще и понятнее использовать предоставленный синтаксис - постоянный указатель на энергозависимую ячейку памяти.

Например, для программ для ПК: если вы разрабатываете игры для DOS VGA (в Интернете есть обучающие программы, которые интересно изучать базовую низкоуровневую графику), то вам нужно записать в память VGA, что может быть указано как смещение из константного указателя.

-Адам

Это позволяет защитить указатель от изменения. Это означает, что вы можете защитить свои предположения, основываясь на том, что указатель никогда не изменяется, или от непреднамеренного изменения, например:

int* const p = &i;

...

p++;     /* Compiler error, oops you meant */
(*p)++;  /* Increment the number */

Другой пример: если вы знаете, где он был инициализирован, вы можете избежать будущих проверок NULL. Компилятор гарантирует, что указатель никогда не менялся (на NULL)…

В любой неконстантной функции-члене C++ this указатель имеет тип C * const, где C это тип класса - вы можете изменить то, на что он указывает (т.е. его члены), но вы не можете изменить его, чтобы он указывал на другой экземпляр C, За const функции-члены, this имеет тип const C * const, Есть также (редко встречаются) volatile а также const volatile функции-члены, для которых this также имеет volatile Классификатор.

Одно из применений - низкоуровневый (драйвер устройства или встроенный) код, в котором необходимо указать конкретный адрес, который сопоставлен с устройством ввода / вывода, например аппаратный вывод. Некоторые языки позволяют связывать переменные по определенным адресам (например, Ада имеет use at). В Си самый идиоматический способ сделать это - объявить постоянный указатель. Обратите внимание, что такие использования должны также иметь volatile Классификатор.

В других случаях это просто защитное кодирование. Если у вас есть указатель, который не должен изменяться, разумно объявить его так, чтобы он не мог измениться. Это позволит компилятору (и инструментам lint) обнаружить ошибочные попытки изменить его.

Я всегда использовал их, когда хотел избежать непреднамеренного изменения указателя (например, арифметики указателя или внутри функции). Вы также можете использовать их для шаблонов Singleton.

this это жестко заданный постоянный указатель.

То же, что и "const int" ... если компилятор знает, что он не изменится, это могут быть предположения об оптимизации, основанные на этом.

struct MyClass
{
    char* const ptr;
    MyClass(char* str) :ptr(str) {}

    void SomeFunc(MyOtherClass moc)
    {
         for(int i=0; i < 100; ++i)
         { 
                 printf("%c", ptr[i]);
                 moc.SomeOtherFunc(this);
         }
    }
}

Теперь компилятор может сделать немного для оптимизации этого цикла - при условии, что он знает, что SomeOtherFunc() не меняет значение ptr. С помощью const компилятор знает это и может делать предположения. Без этого компилятор должен предполагать, что SomeOtherFunc изменит ptr.

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

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

У меня, конечно, нет данных, чтобы поддержать эту догадку, но я все равно сделал бы ставку.

Думайте о типе * и константном типе * как о самих типах. Затем вы можете понять, почему вы можете захотеть иметь const этих типов.

Всегда думайте о указателе как о int. это означает, что

object* var;

на самом деле можно думать как

int var;

Итак, указатель const просто означает, что:

const object* var;

становится

const int var;

и, следовательно, вы не можете изменить адрес, на который указывает указатель, и на этом все. Чтобы предотвратить изменение данных, вы должны сделать его указателем на объект const.

Другие вопросы по тегам