無効なデフォルト値は、基本的にデザインのバリエーションです。オブジェクトは、作成時に無効です。それが合理的であるとき、あなたはそれを避けるべきです。決してそれを「絶対に」避けるべきではありません。
一部の問題では、バリアント状態で開始する必要があります。その場合、あなたはその無効な値について精神的に推論しなければなりません。名前を付けないようにすると、コードの表現力が低下します。あなたと後でコードを維持しなければならない人との間のコミュニケーションの観点からそれについて考えてください。
風下でそれに対処するのは面倒です。あなたはバリアント状態で開始しますが、それが適切になるまでに、それがもはやバリアントではないことを望んでいます。私が好む戦略は、ユーザーがバリアントの状態を無視して、間違えたときにスローすることを許可することです。
namespace FooType {
enum EnumValue {
INVALID = 0
,valid
};
}
struct Foo {
Foo() : val(FooType::INVALID) {}
FooType::EnumValue get() const {
if (val == FooType::INVALID)
throw std::logic_error("variant Foo state");
return val;
}
FooType::EnumValue val;
};
これにより、ユーザーは、戦う価値のある差異について推論する必要がなくなります。
それを回避できない場合、私は通常、安全なインターフェイスと安全でないインターフェイスに劣化することを好みます。
struct Foo {
Foo() : val(FooType::INVALID) {}
bool get(FooType::EnumValue& val_) const {
if (val == FooType::INVALID)
return false;
val_ = val;
return true;
}
FooType::EnumValue get() const {
FooType::EnumValue val_;
if (!get(val_))
throw std::logic_error("variant Foo state");
return val_;
}
FooType::EnumValue get_or_default(FooType::EnumValue def) const {
FooType::EnumValue val_;
if (!get(val_))
return def;
return val_;
}
FooType::EnumValue val;
};
これらの種類のインターフェースは、null値が予想されるデータベースなどに適しています。