Подтвердить что ты не робот

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

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

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

...


object x;

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

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

Это правда?

4b9b3361

Ответ 1

const относится к семантике программы, а не к деталям реализации. Вы должны пометить функцию-член const, когда она не изменит видимое состояние объекта и должна быть вызвана для объекта, который сам является const. Внутри функции const member в классе 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, но не на указательных данных, поэтому вы можете изменить данные, привязанные к указанию.

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

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

Ответ 2

Нет.

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

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


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

Ответ 9

Методам

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

class Foo
{
public:
    int bar() const
    {
        static int x = 0;
        return x++;
    }
};