可能性のある複製:
C++ではnull可能値
C++でnull可能なメンバーを表す最良の方法は何ですか?
C#では、Nullable<T>
タイプを使用できます。すべてが意味のある値を持つことができるわけではないため、このようなデータ型は非常に必要です。 @ Jon Skeet が27ページにまたがる1つの章全体を費やし、優れた本でNullable<T>
のみを説明しているほど重要なデータ型です C#in Depth 。
簡単な例の1つはPerson
クラスです。1、次のように定義されます。
struct Person
{
std::string Name;
DateTime Birth;
DateTime Death;
//...
};
人は常に生年月日を持っているので、上記のクラスのBirth
メンバーには常にいくつかの意味のある値があります。しかし、Death
はどうですか?その人が生きているなら、それはどのような価値があるでしょうか? C#では、このメンバーはNullable<DataTime>
として宣言できます2 これは、人物が生きている場合はnull
で割り当てることができます。
C++では、これを解決する最良の方法は何ですか?今のところ、私が考えている解決策は1つだけです。メンバーをpointerとして宣言します。
DataTime *Death;
これで、人が生きているときの値はnullptr
になります。しかし、死者にはnew
の使用を強制します。有効な値になるからです。これは、コンパイラによって生成されたdefault copy-semanticコードに依存できないことを意味します。プログラマーは つの規則 (C++ 03)に従ってコピーコンストラクター、コピー割り当て、デストラクターを記述する必要があります。またはC++ 11では 5つの規則 です。
では、この問題を単にpointerにするよりも優れたエレガントな解決策はありますか?
1.他の例には、リレーショナルデータベーステーブルが含まれます。
2.これの省略形もあります。 DataTime?
は正確にNullable<DateTime>
と同じです。
あなたは Boost.Optional を調べることができます:
_struct Person
{
std::string Name;
DateTime Birth;
boost::optional<DateTime> Death;
//...
};
_
Death
は最初は「初期化されていません」。=
_のように、_Death = myDateTime
_を使用して値を割り当てることができます。Death.is_initialized()
の場合、Death.get()
を使用できます。Death.reset()
で再度初期化を解除します。ただし、このような単純なケースでは、通常、たとえばDateTime
の「0000-00-00 00:00:00」のような独自の露骨なセンチネル値を選択する方が一貫性があると考えられます。
DateTime
に依存-@Tomalakが答えで言うように、boost::optional<>
は一般的なソリューションです。ただし、たとえば、DateTime
がboost::posix_time::ptime
の場合、すでに特別な値がサポートされています(たとえば、not_a_date_time
またはpos_infin
)-これらを使用できます。
私が取り組んだすべてのプロジェクトには、ある種のFallible
、Maybe
、またはNullable
テンプレートクラスがありました。 (実際の名前は、アプリケーションが最初にそれを必要としたものを反映する傾向があります:戻り値としてのFallible
、モデルデータベースへのNullable
など)。最近では、Boostがboost::optional
;残念ながら、それらはisValid
(名前付き)関数の代わりに暗黙の変換を使用します。その結果、コードが著しく読みにくくなります(おそらく、独自のMaybe
を実装することを除いて、コードを避けたくなるほどです)。 )。
プログラマーの軍団があなたの前にしたことをすることができます! 「存在しない」として特定の値を使用します...たとえば、「2000年1月1日」がかなり一般的であると聞きました:-) :-)相互運用性の理由から、「2038年1月19日03:14:07 UTC」を使用できます。 :-) :-)(それが明確でない場合、それは冗談です。私はY2K問題とY2038問題を参照しています。「特別な」日付を状態として使用する問題を示しています... 11のようなもの-11-11および類似)
DataTime
の最大値/最小値はおそらくより正確です:-)そして、「状態」と「値」を混合しているため、それはまだ間違っています。 C++でNullable
型を再構築することをお勧めします(結局、それは非常に簡単です:null/not nullのブール値とTフィールドを持つテンプレートクラス)
死がいつになる可能性は特に低いため、before birth最初にbirth-1に設定して、実際のイベントで変更することもできます。より一般的な用語では、おそらくbirth-1をセンチネル値またはプレースホルダー値と呼びます。実際の値と間違われないように十分に低い定数値を選択することもできますが、これはデータについてある程度の知識があることを前提としています。