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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7645578/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:16:41  来源:igfitidea点击:

Best way to represent Nullable member in C++?

c++nullablec++11

提问by Nawaz

Possible Duplicate:
Nullable values in C++

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

What is the best way to represent nullable member in C++?

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

In C#, we can use Nullable<T>type. Such a data type is very much needed as not everything can have meaningfulvalue. It is so important data type that @Jon Skeethas spent one entire chapter, spanned over 27 pages, describing only Nullable<T>in his outstanding book C# in Depth.

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

One simple example can be a Personclass1, defined as:

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

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

As a person always have birthdate, so the Birthmember of the above class will always have some meaningfulvalue. But how about Death? What should it value be if the person is alive? In C#, this member can be declared as Nullable<DataTime>2which can be assigned with nullif the person is alive.

作为一个人总是有生日的,所以Birth上面的类的成员总是会有一些有意义的价值。但是Death呢?如果这个人还活着,它的价值应该是多少?在 C# 中,可以将此成员声明为Nullable<DataTime>2null如果此人还活着,则可以将其赋值。

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:

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

 DataTime *Death;

Now its value can be nullptrwhen the person is alive. But it forces the use of newfor dead person, as it's going to have some valid value. It in turn implies one cannot rely on the defaultcopy-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.

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

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.

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

2. There is also a shorthand for this. One can write DataTime?which is exactlysame as Nullable<DateTime>.

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

回答by Lightness Races in Orbit

You could look into Boost.Optional:

你可以看看Boost.Optional

struct Person
{
  std::string               Name;
  DateTime                  Birth;
  boost::optional<DateTime> Death;
  //...
};
  • Your Deathis "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().
  • 你一开始Death是“未初始化的”。
  • 然后,您可以使用 为它分配一个值=,例如Death = myDateTime
  • Death.is_initialized(),您可以使用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 DateTimeof "0000-00-00 00:00:00".

但是,对于像这样的简单情况,通常认为只选择您自己的明显标记值(例如DateTime“0000-00-00 00:00:00”)会更加连贯。

回答by Nim

Depends on DateTime- like @Tomalak says in his answer, boost::optional<>is a generic solution. However if for example your DateTimeis a boost::posix_time::ptime, then there is already support for special values(for example not_a_date_timeor pos_infin) - you could use these.

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

回答by James Kanze

Every project I've worked on has had some sort of Fallible, Maybeor Nullabletemplate class. (The actual name tends to reflect what the application first needed it for: Fallibleas a return value, Nullableto 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).

我参与过的每个项目都有某种Fallible,MaybeNullable模板类。(实际名称往往反映了应用程序最初需要它的用途:Fallible作为返回值、 Nullable对数据库进行建模等)。最近,Boost 引入了boost::optional; 遗憾的是,他们使用隐式转换而不是isValid(命名)函数,这导致代码的可读性明显降低(以至于我会避免它,除非可能实现我自己的Maybe)。

回答by xanatos

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)

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

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

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

回答by mtijn

as death is particularly unlikely to be any time beforebirth 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.

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

回答by WebMonster

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.

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