Какова семантика константной функции-члена?

StackOverflow https://stackoverflow.com/questions/98705

  •  01-07-2019
  •  | 
  •  

Вопрос

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

class object
{
    int get_value(int n) const
    {
        ...
    }

...


object x;

int a = x.get_value(1);
    ...
int b = x.get_value(1);

тогда компилятор мог бы оптимизировать второй вызов и либо использовать значение в регистре, либо просто выполнить b = a;

Это правда?

Это было полезно?

Решение

const речь идет о семантике программы, а не о деталях реализации.Вы должны отметить функцию-член const когда он не меняет видимое состояние объекта и его следует вызывать для объекта, который сам по себе является const.В течение const функция-член класса X, тип this является X const *:указатель на константу X объект.Таким образом, все переменные-члены эффективно const внутри этой функции-члена (за исключением mutable те).Если у тебя есть const объект, вы можете позвонить только const функции-члены на нем.

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

class X
{
    int data;
    mutable boost::mutex m;
public:
    void set_data(int i)
    {
        boost::lock_guard<boost::mutex> lk(m);
        data=i;
    }
    int get_data() const // we want to be able to get the data on a const object
    {
        boost::lock_guard<boost::mutex> lk(m); // this requires m to be non-const
        return data;
    }
};

Если вы храните данные с помощью указателя, а не напрямую (включая интеллектуальные указатели, такие как std::auto_ptr или boost::shared_ptr) тогда указатель станет const в const функцию-член, но не данные, на которые указывают, поэтому вы можете изменить данные, на которые указывает.

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

Следующая версия программы Стандарт C++ (C++0x) будет новое ключевое слово constexpr.Функции с тегами constexpr возвращайте постоянное значение, чтобы результаты можно было кэшировать.Существуют ограничения на то, что вы можете делать в такой функции (чтобы компилятор мог проверить этот факт).

Другие советы

Ключевое слово изменчивый on переменных-членов позволяет константным функциям изменять состояние объекта под рукой.

И нет, он не кэширует данные (по крайней мере, не все вызовы), поскольку следующий код является допустимой константной функцией, которая меняется со временем:

int something() const { return m_pSomeObject->NextValue(); }

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

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

Нет.

Константный метод — это метод, который не меняет состояние объекта (т.его поля), но вы не можете предполагать, что при одних и тех же входных данных определяется возвращаемое значение константного метода.Другими словами, const Ключевое слово НЕ подразумевает, что функция является взаимно однозначной.Например, метод, который возвращает текущее время, является константным методом, но его возвращаемое значение меняется между вызовами.

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

В этом контексте const функция-член означает, что this рассматривается как const указатель также.На практике это означает, что вам не разрешено изменять состояние this внутри const функция-член.

Для функций без побочных эффектов (то есть того, чего вы пытаетесь достичь) GCC имеет «атрибут функции», называемый pure (вы используете его, говоря __attribute__((pure))): http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

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

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

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

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


Редактировать:Блин, обыграли на 9 секунд....9!!!:)

Константным методам также разрешено изменять статические локальные значения.Например, следующее совершенно законно (и повторные вызовы bar() будут возвращать возрастающие значения, а не кэшированный 0):

class Foo
{
public:
    int bar() const
    {
        static int x = 0;
        return x++;
    }
};
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top