Попытка собрать несколько использований:
Связывание некоторого временного объекта со ссылкой на 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) {
// ...
}