在C ++中表示Nullable成员的最佳方法?

时间:2011-10-04 09:08:45

标签: c++ nullable c++11

  

可能重复:
  Nullable values in C++

在C ++中表示可空成员的最佳方法是什么?

在C#中,我们可以使用Nullable<T>类型。非常需要这样的数据类型,因为并非所有内容都具有有意义的值。这是一个非常重要的数据类型,@Jon Skeet已经花了整整一章,跨越了27页,在他的优秀书C# in Depth中只描述了Nullable<T>

一个简单的例子可以是Person 1 ,定义为:

struct Person
{
  std::string Name;
  DateTime    Birth;
  DateTime    Death;
  //...
};

由于一个人总是有生日,所以上述类的Birth成员总是会有一些有意义的值。但Death怎么样?如果这个人还活着,它应该有什么价值呢?在C#中,此成员可以声明为Nullable<DataTime> 2 ,如果此人活着,可以使用null进行分配。

在C ++中,解决这个问题的最佳方法是什么?截至目前,我只考虑了一个解决方案:将成员声明为指针

 DataTime *Death;

现在,当这个人还活着时,它的值可以是nullptr。但它迫使new用于死人,因为它会有一些有效的价值。它反过来意味着不能依赖编译器生成的默认复制语义代码。程序员必须在rule of three(C ++ 03)之后编写复制构造函数,复制赋值,析构函数,或者在C ++ 11中编写rule of five

对于这个问题,我们是否有更好,更优雅的解决方案,而不仅仅是指针


1。其他示例包括关系数据库表,因为在许多DBMS列中可以为空。功能

2。还有一个简写。可以写DataTime? Nullable<DateTime>完全相同。功能

6 个答案:

答案 0 :(得分:39)

您可以查看Boost.Optional

struct Person
{
  std::string               Name;
  DateTime                  Birth;
  boost::optional<DateTime> Death;
  //...
};
  • 您的Death最初是“未初始化的”。
  • 然后,您可以使用=Death = myDateTime分配值,例如Death.is_initialized()
  • Death.get()时,您可以使用Death.reset()
  • 使用DateTime再次取消初始化。

对于像这样的简单案例,通常认为选择你自己公然的哨兵价值更为连贯,例如,{00} 00:00的“{1}}”。

答案 1 :(得分:6)

取决于DateTime - 就像@Tomalak在回答中所说,boost::optional<>是一种通用的解决方案。但是,如果您的DateTimeboost::posix_time::ptime,则表示已支持特殊值(例如not_a_date_timepos_infin) - 您可以使用这些。

答案 2 :(得分:5)

我参与过的每个项目都有某种FallibleMaybeNullable模板类。 (实际名称倾向于反映出什么 应用程序首先需要它:Fallible作为返回值, Nullable来建模数据库等)。最近,Boost有了 介绍boost::optional;遗憾的是,他们使用隐式转换 而不是isValid(命名)函数,这导致显着 不太可读的代码(我可以避免它,除了可能的 实现我自己的Maybe)。

答案 3 :(得分:1)

你可以做大量的程序员在你之前做的事情!使用特定值作为“不存在”...例如我听说“2000年1月1日”很常见:-) :-)出于互操作性原因,您可以使用“19 Jan 2038 03:14:07 UTC” :-) :-)(这是一个笑话,如果不清楚。我正在引用Y2K问题和Y2038问题。我正在展示使用“特殊”日期作为状态的问题......像11这样的事情-11-11和类似的)

DataTime的最大值/最小值可能更正确:-)而且它仍然是错误的,因为您正在混合“状态”和“值”。更好的是你在C ++中重建Nullable类型(最后它很容易:带有bool for null / not null和T字段的模板化类)

答案 4 :(得分:1)

因为死亡特别不可能在出生之前的任何时间出生,你也可以将其设置为出生 - 1最初并且在实际事件中改变它。在更常见的术语中,您可能称为出生 - 1是哨兵值或占位符值。你也可以选择一个足够低的常数值,不要被误认为是真值,但这假设你对数据有一定的了解。

答案 5 :(得分:-2)

我会创建一个表示空值的静态成员,而不是将死亡日期的地址与静态对象的地址进行比较。如果它们相等,则值为NULL。