Possible Duplicate:
Nullable values in C++
What is the best way to represent nullable member in C++?
In C#, we can use Nullable<T>
type. Such a data type is very much needed as not everything can have meaningful value. It is so important data type that @Jon Skeet has spent one entire chapter, spanned over 27 pages, describing only Nullable<T>
in his outstanding book C# in Depth.
One simple example can be a Person
class1, defined as:
struct Person
{
std::string Name;
DateTime Birth;
DateTime Death;
//...
};
As a person always have birthdate, so the Birth
member of the above class will always have some meaningful value. But how about Death
? What should it value be if the person is alive? In C#, this member can be declared as Nullable<DataTime>
2 which can be assigned with null
if the person is alive.
In C++, what is the best way to solve this? As of now, I've only one solution in mind: declare the member as pointer:
DataTime *Death;
Now its value can be nullptr
when the person is alive. But it forces the use of new
for dead person, as it's going to have some valid value. It in turn implies one cannot rely on the default copy-semantic code generated by the compiler. The programmer has to write copy-constructor, copy-assignment, destructor following rule of three (C++03), Or in C++11, rule of five.
So do we have any better, elegant solution to this problem than just making it pointer?
1. Other examples include relational database tables, as in many DBMSs columns can be nullable.
2. There is also a shorthand for this. One can write DataTime?
which is exactly same as Nullable<DateTime>
.
You typically use a nullable value type when you need to represent the undefined value of an underlying value type. For example, a Boolean, or bool , variable can only be either true or false . However, in some applications a variable value can be undefined or missing.
You can declare nullable types using Nullable<t> where T is a type. Nullable<int> i = null; A nullable type can represent the correct range of values for its underlying value type, plus an additional null value. For example, Nullable<int> can be assigned any value from -2147483648 to 2147483647, or a null value.
Nullable types have two properties. HasValue: This property returns a bool value based on that if the Nullable variable has some value or not. If the variable has some value, then it will return true; otherwise, it will return false if it doesn't have value or it's null.
Although using nullable reference types can introduce its own set of problems, I still think it's beneficial because it helps you find potential bugs and allows you to better express your intent in the code. For new projects, I would recommend you enable the feature and do your best to write code without warnings.
You could look into Boost.Optional:
struct Person { std::string Name; DateTime Birth; boost::optional<DateTime> Death; //... };
Death
is "uninitialised" at first.=
, like Death = myDateTime
.Death.is_initialized()
, you can use Death.get()
.Death.reset()
.For simple cases like this, though, it's usually considered more coherent to just pick your own blatant sentinel value like, say, a DateTime
of "0000-00-00 00:00:00".
Depends on DateTime
- like @Tomalak says in his answer, boost::optional<>
is a generic solution. However if for example your DateTime
is a boost::posix_time::ptime
, then there is already support for special values (for example not_a_date_time
or pos_infin
) - you could use these.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With