2008-09-19 2 views
12

Я понимаю, что функции не разрешено изменять состояние объекта, но я думал, что где-то я прочитал, что компилятору было позволено предположить, что если бы функция вызывалась с теми же аргументами, она возвращала бы такое же значение и, следовательно, может использовать кешированное значение, если оно доступно. напримерКакова семантика функции-члена 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;

ли это?

ответ

22

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

0

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

2

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

+0

На самом деле, если у вас есть член помеченных изменчивый, то константная функция все еще может изменить Это. Это в основном полезно для кэширования последнего результата. :-) – 0124816 2008-09-19 05:29:53

2

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

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

+0

Я не пытаюсь добиться отсутствия побочных эффектов. Я просто хочу понять все последствия создания функции const. – Ferruccio 2008-09-19 01:51:59

3

No.

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

0

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

2

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

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

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

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

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

0

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

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


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

+0

Самый быстрый пистолет на Западе, много? :-P – 2008-09-19 02:02:54

+0

Эй, теперь мой ответ был за 9 секунд до твоего. : P – KTC 2008-09-19 02:10:18

0

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

class Foo 
{ 
public: 
    int bar() const 
    { 
     static int x = 0; 
     return x++; 
    } 
}; 
Смежные вопросы