Какова семантика функции-члена const? - PullRequest
13 голосов
/ 19 сентября 2008

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

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

...


object x;

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

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

Это правда?

Ответы [ 9 ]

24 голосов
/ 19 сентября 2008

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

3 голосов
/ 19 сентября 2008

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

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

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

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

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

3 голосов
/ 19 сентября 2008

Нет.

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

2 голосов
/ 19 сентября 2008

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

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

2 голосов
/ 19 сентября 2008

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

0 голосов
/ 20 сентября 2008

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

class Foo
{
public:
    int bar() const
    {
        static int x = 0;
        return x++;
    }
};
0 голосов
/ 19 сентября 2008

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

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


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

0 голосов
/ 19 сентября 2008

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

0 голосов
/ 19 сентября 2008

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

...