STLイテレータ?
私の前に提案された「イテレーター」のアイデアは興味深いものですが、イテレーターの真の目的はコンテナー内を移動することです。単純なアクセサとしてではありません。
アクセサーが数ある中の 1 つである場合は、イテレーターを使用してコンテナー内を移動できるため、イテレーターが適しています。しかし、アクセサーが単純なゲッターであり、値または値がないという事実を返すことができる場合、イテレーターはおそらく美化されたポインターにすぎません...
それは私たちを導く...
スマートポインター?
スマート ポインターのポイントは、ポインターの所有権を単純化することです。共有ポインターを使用すると、オーバーヘッドを犠牲にして共有されるリソース (メモリ) を取得できます (共有ポインターは参照カウンターとして整数を割り当てる必要があります...)。
選択する必要があります: Value が既に共有ポインター内にある場合、この共有ポインター (または弱いポインター) を返すことができます。またはあなたの値は生のポインタの中にあります。その後、行ポインタを返すことができます。リソースがまだ共有ポインター内にない場合は、共有ポインターを返したくありません。共有ポインターが範囲外になり、通知せずに値を削除すると、面白いことが起こります...
:-p
ポインタ?
インターフェイスがそのリソースの所有権について明確であり、返される値が NULL になる可能性があるという事実によって、単純な生のポインターを返すことができます。コードのユーザーが、オブジェクトのインターフェイス コントラクトを無視したり、ポインタを使って算術演算を行ったりするほど愚かな場合、値を返すために選択する他の方法を破るほど愚かになります。知的障害者は気にしないでください...
未定義の値
Value 型が実際に何らかの「未定義」の値を持っていて、ユーザーがそれを知っていて、それを処理することを受け入れる場合を除き、ポインターまたはイテレーターのソリューションと同様に、それは可能な解決策です。
しかし、あなたが尋ねた問題のために、「未定義」の値を Value クラスに追加しないでください。「参照対ポインター」戦争を別のレベルの狂気に引き上げることになります。コードのユーザーは、与えられたオブジェクトが正常であること、または存在しないことを望んでいます。このオブジェクトがまだ有効であるコードを 1 行おきにテストする必要があるのは苦痛であり、ユーザー コードを無駄に複雑にしてしまいます。
例外
例外は通常、一部の人々が望んでいるほどコストがかかりません。ただし、単純なアクセサーの場合、アクセサーが頻繁に使用される場合、コストは簡単ではありません。
たとえば、STL std::vector には、インデックスを介してその値への 2 つのアクセサーがあります。
T & std::vector::operator[]( /* index */ )
と:
T & std::vector::at( /* index */ )
違いは、[]
が投げないことです。そのため、ベクトルの範囲外にアクセスすると、おそらくメモリの破損や遅かれ早かれクラッシュする危険性があります。したがって、それを使用してコードを検証したことを本当に確認する必要があります。
一方、投げat
ています。これは、ベクトルの範囲外にアクセスすると、クリーンな例外が発生することを意味します。エラーの処理を別のコードに委任したい場合は、この方法が適しています。
[]
ループ内の値にアクセスするときなどに個人的に使用します。私at
は、例外が現在のコード (または呼び出し元のコード) を返す良い方法であると感じたときに、何かがうまくいかなかったという事実を使用します。
だから何?
あなたの場合、次を選択する必要があります。
非常に高速なアクセスが本当に必要な場合は、スローするアクセサーが問題になる可能性があります。しかし、これは、コードで既にプロファイラーを使用して、これがボトルネックであると判断したことを意味しますね。
;-)
値がないことが頻繁に発生する可能性があることがわかっている場合、および/またはクライアントに、アクセスされた値への可能なnull/無効/その他のセマンティックポインターを伝播させたい場合は、ポインターを返します(値が単純なポインター内にある場合)または弱い/共有ポインター (値が共有ポインターによって所有されている場合)。
ただし、クライアントがこの "null" 値を伝達しない、またはコード内で NULL ポインター (またはスマート ポインター) を伝達すべきではないと思われる場合は、例外によって保護された参照を使用します。ブール値を返す「hasValue」メソッドを追加し、値がない場合でもユーザーが値を取得しようとした場合にスローを追加します。
最後になりましたが、オブジェクトのユーザーが使用するコードを検討してください。
// If you want your user to have this kind of code, then choose either
// pointer or smart pointer solution
void doSomething(MyClass & p_oMyClass)
{
MyValue * pValue = p_oMyClass.getValue() ;
if(pValue != NULL)
{
// Etc.
}
}
MyValue * doSomethingElseAndReturnValue(MyClass & p_oMyClass)
{
MyValue * pValue = p_oMyClass.getValue() ;
if(pValue != NULL)
{
// Etc.
}
return pValue ;
}
// ==========================================================
// If you want your user to have this kind of code, then choose the
// throwing reference solution
void doSomething(MyClass & p_oMyClass)
{
if(p_oMyClass.hasValue())
{
MyValue & oValue = p_oMyClass.getValue() ;
}
}
したがって、主な問題が上記の 2 つのユーザー コードのどちらかを選択することである場合、問題はパフォーマンスではなく、「コードのエルゴノミー」です。したがって、パフォーマンスの問題が発生する可能性があるため、例外ソリューションを脇に置くべきではありません。
:-)