когда функция-член должна быть одновременно const и volatile? - PullRequest
10 голосов
/ 17 марта 2009

Я читал о функции volatile-члена и натолкнулся на утверждение, что функция-член может быть одновременно const и volatile . Я не получил реального использования такой вещи. Может кто-нибудь поделиться, пожалуйста, своим опытом практического использования наличия функции-члена как const и volatile вместе.

Я написал небольшой класс, чтобы проверить то же самое:

class Temp
{
public:

    Temp(int x) : X(x)
    {
    }

    int getX() const volatile
    {
        return X;
    }

    int getBiggerX()
    {
        return X + 10;
    }
private:
    int X;
};

void test( const volatile Temp& aTemp)
{
    int x = aTemp.getX();
}

int main(int argc, char* argv[])
{
    const volatile Temp aTemp(10);
    test(aTemp);

    return 0;
}

Ответы [ 6 ]

17 голосов
/ 17 марта 2009

Дистиллированная квалификация cv означает:

Я не буду менять значение, но есть кое-что, что может.

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

Практический вариант использования этого - системные часы. Предположим, что 0xDEADBEEF был вашим системным адресом регистра аппаратных часов, который вы написали бы:

int const volatile *c = reinterpret_cast<int *>(0xDEADBEEF);

Вы не можете изменить это значение регистра, но каждый раз, когда вы читаете его, оно может иметь другое значение.

Также можно использовать это для модели UARTs .

13 голосов
/ 17 марта 2009

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

Однако давайте добавим в него постоянную изменчивую функцию только для того, чтобы ответить на вопрос. Предположим, у вас есть порт с адресом 0x378h, который содержит 2 целых числа по 4 байта. Тогда вы могли бы написать

struct ints {
    int first;
    int second;
    int getfirst() const volatile {
        return first;
    }

    int getsecond() const volatile {
        return second;
    }
      // note that you could also overload on volatile-ness, just like
      // with const-ness
};

// could also be mapped by the linker. 
ints const volatile &p = *reinterpret_cast<ints*>(0x378L);

Вы заявляете

Я не изменяю их, но другая вещь вне этой абстрактной семантики может изменить это. Поэтому всегда делайте реальную загрузку со своего адреса.

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

a = 4;
a *= 2; 
  // can't be optimized to a = 8; if a is volatile because the abstract
  // semantics described by the language contain two assignments and one load.

Следующее уже определяет, что делает volatile. Все можно найти в 1.9 стандарта. Параметры, о которых он говорит, это вещи, определяемые реализацией, например, sizeof некоторого типа.

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

Соответствующая реализация, выполняющая правильно сформированную программу, должна производить то же наблюдаемое поведение, что и одна из возможных последовательностей выполнения соответствующего экземпляра абстрактной машины с той же программой и тем же вводом. [...]

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

1 голос
/ 17 марта 2013

Объект, помеченный как const volatile, не будет изменен кодом, в котором он объявлен. Ошибка будет вызвана из-за спецификатора const. Изменчивая часть спецификатора означает, что компилятор не может оптимизировать код относительно объекта.

Во встроенной системе это обычно используется для доступа к аппаратным регистрам, которые могут считываться и обновляться аппаратными средствами, поэтому нет смысла иметь возможность записи в регистр с помощью кода. Примером может служить регистр состояния последовательного порта. Различные биты будут указывать состояние, например, если символ ожидает чтения. Каждое чтение в этот регистр состояния может привести к различному значению в зависимости от того, что еще произошло в оборудовании последовательного порта. Нет смысла записывать данные в регистр состояния, но необходимо убедиться, что каждое чтение регистра приводит к фактическому чтению аппаратного обеспечения.

Ниже приведена иллюстрация:

//We assume that the below declared pointers
//point to the correct
//hardware addresses
unsigned int const volatile *status_reg;
unsigned char const volatile *recv_reg;

#define CHAR_READ 0x01

int get_next_char()
{
    while((*status_reg & CHAR_READ) == 0);
    return *recv_reg;
}

Надеюсь, это поможет.

С уважением Сандипан Кармакар.

1 голос
/ 18 марта 2009

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

1 голос
/ 17 марта 2009

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

1 голос
/ 17 марта 2009

Мне никогда не требовалось, чтобы что-то было постоянным и изменчивым, но вот мое предположение:

Const : Вы, ваш код, не можете изменять значение.

Volatile : значение может меняться со временем, если ваша программа ничего не делает.

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

...