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

Naw*_*waz 32 c++ nullable c++11

可能重复:
C++中的Nullable值

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

在C#中,我们可以使用Nullable<T>类型.非常需要这样的数据类型,因为并非所有数据都具有有意义的价值.这是一个非常重要的数据类型,@ Jon Skeet花了整整一章,跨越了27页,仅Nullable<T>在他的优秀着作C#Depth中进行了描述.

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

struct Person
{
  std::string Name;
  DateTime    Birth;
  DateTime    Death;
  //...
};
Run Code Online (Sandbox Code Playgroud)

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

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

 DataTime *Death;
Run Code Online (Sandbox Code Playgroud)

现在它的价值可以是nullptr人活着的时候.但它强迫使用new死人,因为它会有一些有效的价值.它反过来意味着不能依赖编译器生成的默认复制语义代码.程序员必须编写复制构造函数,复制赋值,析构函数遵循三条规则(C++ 03),或者在C++ 11中规则,五条规则.

那么,除了制作指针之外,我们还有更好,更优雅的解决方案吗?


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

这也有一个简写.人们可以写DataTime?正是因为相同Nullable<DateTime>.

Lig*_*ica 39

你可以看看Boost.Optional:

struct Person
{
  std::string               Name;
  DateTime                  Birth;
  boost::optional<DateTime> Death;
  //...
};
Run Code Online (Sandbox Code Playgroud)
  • Death最初是"未初始化的".
  • 然后,您可以为其分配值=,例如Death = myDateTime.
  • 什么时候Death.is_initialized(),你可以使用Death.get().
  • 再次取消初始化Death.reset().

然而,对于像这样的简单情况,通常认为选择你自己的公然哨兵价值更为连贯,例如DateTime"00:00:00".

  • (http://meta.stackexchange.com/questions/9090/is-there-an-editing-grace-period-on-answers-after-they-have-been-posted) (5认同)
  • 不推荐使用`reset`和`is_initialized`.您可以通过为其指定`boost :: none`来取消初始化,并通过转换为bool来测试初始化​​. (5认同)
  • @RedX:我没有编辑答案!总是很棒!;) (2认同)
  • @ TomalakGeret'kal`reset`和`is_initialized`被记录为已弃用.亲身体验:http://www.boost.org/doc/libs/1_47_0/libs/optional/doc/html/boost_optional/synopsis.html.我提供了替代方案:`x = boost :: none`而不是`x.reset()`和`if(x)`而不是`if(x.is_initialized())`. (2认同)

Nim*_*Nim 6

取决于DateTime@Tomalak在他的回答中说,这boost::optional<>是一个通用的解决方案.但是,如果您DateTime是a boost::posix_time::ptime,那么已经支持特殊值(例如not_a_date_timepos_infin) - 您可以使用这些值.


Jam*_*nze 5

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

  • @SteveJessop嗯,你也想摆脱指针操作; 它不是**智能指针,所以它不应该像一个.在许多方面,`boost :: optional`似乎遭遇了特征蠕变.(当然,我的`Fallible`也可以这么说 - 或者可能是其他任何已经存在很长时间且已被用于各种应用程序的类.) (2认同)