回答:
いくつかの用途を収集しようとしています:
一時的なものをreference-to-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); }
このトリックは、Alexandrescuの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; }
};
説明:元のオブジェクトとコピーしたオブジェクトのデータが同じである限り、何かをコピーするときにデータを共有したい場合があります。オブジェクトの1つがデータを変更すると、2つのバージョンが必要になります。1つは元のバージョン、もう1つはコピーです。つまり、どちらかのオブジェクトへの書き込みをコピーして、両方が独自のバージョンを持つようにします。
コードの使用:
int main() {
string const a = "1234";
string const b = a;
// outputs the same address for COW strings
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
上記のスニペットは、使用されているC ++ライブラリがcopy-on-writeを実装しているため、私のGCCに同じアドレスを出力しますstd::string
。両方の文字列は、個別のオブジェクトですが、文字列データ用に同じメモリを共有しています。作るb
非constはの非constバージョンを好むだろうoperator[]
し、我々はそれを変更する可能性があるため、GCCは、バッキング・メモリ・バッファのコピーを作成し、それがデータに影響を与えてはいけませんa
!
int main() {
string const a = "1234";
string b = a;
// outputs different addresses!
cout << (void*)&a[0] << ", " << (void*)&b[0];
}
コピーコンストラクターがconstオブジェクトおよび一時オブジェクトからコピーを作成するため:
struct MyClass {
MyClass(MyClass const& that) { /* make copy of that */ }
};
ささいに変更できない定数を作るために
double const PI = 3.1415;
値ではなく参照で任意のオブジェクトを渡す場合 -高価または不可能な値渡しを防ぐため
void PrintIt(Object const& obj) {
// ...
}
C ++でのconstの主な使用法は2つあります。
定数値
値が、その存続期間中に変更されない(または変更されない)変数、メンバー、またはパラメーターの形式である場合は、constとマークする必要があります。これにより、オブジェクトの変更を防ぐことができます。たとえば、次の関数では、渡されたStudentインスタンスを変更する必要がないため、constとマークしています。
void PrintStudent(const Student& student) {
cout << student.GetName();
}
なぜそうするのか。基本となるデータが変更できないことがわかっている場合は、アルゴリズムについて推論する方がはるかに簡単です。「const」は役立ちますが、これが達成されることを保証するものではありません。
当然のことながら、データをcoutに出力するのにそれほど多くの考慮は必要ありません。
メンバーメソッドをconstとしてマーク
前の例では、学生をconstとしてマークしました。しかし、C ++は、学生でGetName()メソッドを呼び出してもオブジェクトが変更されないことをどのようにして知りましたか?答えは、メソッドがconstとしてマークされたことです。
class Student {
public:
string GetName() const { ... }
};
メソッドを「const」とマークすると、2つのことが行われます。主に、このメソッドはオブジェクトを変更しないことをC ++に伝えます。2つ目は、すべてのメンバー変数がconstとしてマークされているかのように処理されることです。これは役立ちますが、クラスのインスタンスを変更できます。
これは非常に単純な例ですが、うまくいけば、質問への回答に役立つでしょう。
これらの4つの宣言の違いを理解するように注意してください。
次の2つの宣言は、意味的に同じです。ccp1とccp2が指す場所は変更できますが、それらが指しているものは変更できません。
const char* ccp1;
char const* ccp2;
次に、ポインターはconstなので、意味をなすには、何かを指すように初期化する必要があります。それを別のものに向けることはできませんが、それが指すものは変更することができます。
char* const cpc = &something_possibly_not_const;
最後に、2つを結合します。つまり、ポイントされているものは変更できず、ポインターは他のどこもポイントできません。
const char* const ccpc = &const_obj;
時計回りのスパイラルルールは、宣言のもつれをほどくのに役立ちますhttp://c-faq.com/decl/spiral.anderson.html