开发者

Best way to represent Nullable member in C++? [duplicate]

This question already has answers here: Closed 11 years ago.

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 incl开发者_如何学运维ude 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 could look into Boost.Optional:

struct Person
{
  std::string               Name;
  DateTime                  Birth;
  boost::optional<DateTime> Death;
  //...
};
  • Your Death is "uninitialised" at first.
  • You can then assign a value to it with =, like Death = myDateTime.
  • When Death.is_initialized(), you can use Death.get().
  • Uninitialise it again with 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.


Every project I've worked on has had some sort of Fallible, Maybe or Nullable template class. (The actual name tends to reflect what the application first needed it for: Fallible as a return value, Nullable to model databases, etc.). More recently, Boost has introduced boost::optional; regretfully, they use implicit conversions instead of an isValid (named) function, which results in noticeably less readable code (to the point where I'd avoid it, except maybe to implement my own Maybe).


as death is particularly unlikely to be any time before birth you could just as well set it to birth - 1 initially and have it changed on the actual event. in more common terms you'd probably call birth - 1 a sentinel value or placeholder value. you could also pick a constant value low enough not to be mistaken for a real value, but that assumes you have some knowledge of your data.


You can do what legions of programmers did before you! Use a specific value as "not present"... For example I've heard that "1 Jan 2000" was pretty common :-) :-) For interoperability reasons you could use "19 Jan 2038 03:14:07 UTC" :-) :-) (it's a joke, if it isn't clear. I'm referencing the Y2K problem and the Y2038 problem. I'm showing the problem of using "special" dates as states... Things like 11-11-11 and similar)

The maximum/minimum value of your DataTime is probably more correct :-) And it's still wrong, because you are mixing a "state" with a "value". Better that you rebuild the Nullable type in C++ (in the end it's quite easy: a templated class with a bool for null/not null and the T field)


I would create a static member which represent null value, than compare the address of date of death to the address of the static object. If they are equal the value is NULL.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜