Сколько и как используются слова «const» в C ++? - PullRequest
120 голосов
/ 18 января 2009

Как начинающему программисту на C ++, есть некоторые конструкции, которые кажутся мне очень неясными, одна из них - const. Вы можете использовать его во многих местах и ​​с таким количеством различных эффектов, что для новичка практически невозможно выйти живым. Будет ли когда-нибудь вечно гуру C ++ объяснять различные варианты использования, и / или почему не стоит их использовать?

Ответы [ 4 ]

98 голосов
/ 18 января 2009

Попытка собрать несколько использований:

Связывание некоторого временного объекта со ссылкой на const для увеличения его времени жизни. Ссылка может быть основой - и ее деструктор не обязательно должен быть виртуальным - правильный деструктор все еще называется :

ScopeGuard const& guard = MakeGuard(&cleanUpFunction);

Пояснение , используя код:

struct ScopeGuard { 
    ~ScopeGuard() { } // not virtual
};

template<typename T> struct Derived : ScopeGuard { 
    T t; 
    Derived(T t):t(t) { }
    ~Derived() {
        t(); // call function
    }
};

template<typename T> Derived<T> MakeGuard(T t) { return Derived<T>(t); }

Этот прием используется в служебном классе Александреску ScopeGuard. Когда временный объект выходит из области видимости, деструктор Derived вызывается правильно. Приведенный выше код пропускает некоторые мелкие детали, но это большая проблема.


Используйте const, чтобы указать, что другие методы не изменят логическое состояние этого объекта.

struct SmartPtr {
    int getCopies() const { return mCopiesMade; }
};

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

struct MyString {
    char * getData() { /* copy: caller might write */ return mData; }
    char const* getData() const { return mData; }
};

Объяснение : Возможно, вы захотите поделиться данными, когда копируете что-то, пока данные оригинального и копируемого объекта остаются прежними. После того, как один из объектов изменит данные, вам теперь понадобятся две версии: одна для оригинала и одна для копии. То есть вы копируете на и записываете в любой объект, так что теперь они оба имеют свою собственную версию.

Использование кода :

int main() {
    string const a = "1234";
    string const b = a;
    // outputs the same address for COW strings
    cout << (void*)&a[0] << ", " << (void*)&b[0];
}

Приведенный выше фрагмент печатает тот же адрес на моем GCC, потому что используемая библиотека C ++ реализует копирование при записи std::string. Обе строки, даже если они являются отдельными объектами, совместно используют одну и ту же память для своих строковых данных. Если сделать b неконстантным, предпочтет неконстантную версию operator[], а GCC создаст копию буфера резервной памяти, потому что мы можем изменить его, и это не должно влиять на данные a!

int main() {
    string const a = "1234";
    string b = a;
    // outputs different addresses!
    cout << (void*)&a[0] << ", " << (void*)&b[0];
}

Для конструктора копирования для создания копий из постоянных объектов и временных объектов :

struct MyClass {
    MyClass(MyClass const& that) { /* make copy of that */ }
};

Для создания констант, которые тривиально невозможно изменить

double const PI = 3.1415;

Для передачи произвольных объектов по ссылке, а не по значению - для предотвращения возможной дорогой или невозможной передачи побочного значения

void PrintIt(Object const& obj) {
    // ...
}
26 голосов
/ 18 января 2009

На самом деле в C ++ есть два основных применения const.

Постоянные значения

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

void PrintStudent(const Student& student) {
  cout << student.GetName();
}

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

Очевидно, что печать данных в cout не требует особых размышлений :)

Пометка метода-члена как const

В предыдущем примере я пометил Student как const. Но как C ++ узнал, что вызов метода GetName () для student не приведет к изменению объекта? Ответ заключается в том, что метод был помечен как постоянный.

class Student {
  public:
    string GetName() const { ... }
};

Маркировка метода "const" делает 2 вещи. В первую очередь это говорит C ++, что этот метод не будет изменять мой объект. Во-вторых, все переменные-члены теперь будут обрабатываться так, как если бы они были помечены как const. Это помогает, но не мешает вам изменять экземпляр вашего класса.

Это очень простой пример, но, надеюсь, он поможет ответить на ваши вопросы.

15 голосов
/ 22 января 2009

Постарайтесь понять разницу между этими 4 декларациями:

Следующие 2 объявления семантически идентичны. Вы можете изменить , где ccp1 и ccp2, но вы не можете изменить то, на что они указывают.

const char* ccp1;
char const* ccp2;

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

char* const cpc = &something_possibly_not_const;

Наконец, мы объединяем два - поэтому объект, на который указывает указатель, не может быть изменен, и указатель не может указывать куда-либо еще.

const char* const ccpc = &const_obj;

Правило спирали по часовой стрелке может помочь распутать объявление http://c -faq.com / decl / spiral.anderson.html

2 голосов
/ 11 мая 2017

В качестве небольшой заметки, когда я читаю здесь , полезно заметить, что

const относится ко всему, что находится непосредственно слева (кроме случаев, когда там нет ничего, в этом случае это относится к тому, что его сразу справа).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...