【问题标题】:How to store some kind of "null" in C++ double or int variable?如何在 C++ double 或 int 变量中存储某种“null”?
【发布时间】:2014-10-22 16:23:04
【问题描述】:

我有一个看起来像这样的课程

struct A {
     double a1;
     int b1;
     double a2;
     int b2;
};

我必须读取a1b1a2b2 的文件值。大多数情况下,所有四个数字都在文件中,但有时只有两个数字。

当有两个数字时,我想将值存储在a1b1 中,并且我想在a2b2 中存储“无”。如果a2b2 是指针,我可以将它们分配为nullptr,但它们不是指针。

我可以在doubleint 变量中存储一些东西来表明“什么都没有”被存储?

我知道Boost.Optional 可用,但我试图避开那个库。

【问题讨论】:

  • 选择一个你知道你的变量永远不会采用的值并将其命名为NULL。然后将变量与NULL 进行比较。首选通常是 0 或 -1
  • 这就是麻烦,我不知道我的变量永远不会有的值。
  • @Josh:不,不要把它命名为NULL。给它一个不与标准库冲突的唯一名称。
  • 如果你出于某种原因真的不想使用 boost 库,为简单类型编写自己的 optional 非常简单 - 只需将值和 bool 包装一点具有合适接口的类。如果您想支持非平凡的类型(特别是不能默认构造的类型),那么使用库将为您省去一个痛苦的世界。
  • 对于浮点,您也许可以使用NaN,但据我所知,对浮点NaN 的支持并不普遍。对于int 类型,INT_MIN 可能 是合理的,但你说你不知道你的变量永远不会有任何值。与指针不同,整数没有明显的“nulL”值。鉴于此,您唯一的选择是存储一些额外信息,指示是否存储了有意义的值。无论您是使用Boost.Optional,还是使用类似于Boost.Optional 的自己的类,还是仅添加bool 成员,都取决于您。

标签: c++ c++11 null


【解决方案1】:
struct A {
     double a1;
     int b1;
     double a2;
     int b2;

};

为此,您可以使用任何类型的变量来指示是否为这些变量分配了两个或四个值。

像取一个变量名赋值 = -1

因此,如果您的输入值是正数,那么如果两个值在文件内,则只需 make

a2 = b2 = 分配

所以当你检查时,只需检查 a2 和 b2 的值是否为 -1 或其他值,

【讨论】:

    【解决方案2】:

    或者,您可以添加额外成员以了解普通成员是否受到影响,例如:

    struct A {
         double a1;
         int b1;
         double a2;
         int b2;
         bool is_assigned[4];
    };
    

    struct A {
         double a1;
         int b1;
         double a2;
         int b2;
         double* p_a1; // point to a1 when initialized, else nullptr
         int* p_b1;    // point to b1 when initialized, else nullptr
         double* p_a2; // point to a2 when initialized, else nullptr
         int* p_b1;    // point to b2 when initialized, else nullptr
    };
    

    【讨论】:

      【解决方案3】:

      看起来您今后会遇到问题。需要知道有多少值是有效的,这将贯穿代码库。

      我建议有一个工厂基类。本质上,您将至少有两个类:

      struct two_values
      {
        double a1;
        int    b1;
      };
      
      struct four_values : public two_values
      {
        double a2;
        int    b2;
      };
      

      当函数明确需要四个值时,请在声明中使用four_values 结构。否则在函数声明中使用two_values 结构。

      这种关系表明four_values 实例可用于任何需要two_values 结构的函数。

      替代方案
      另一种方法是为您的项目使用std::vector

      struct Container
      {
        std::vector<double> a_values;
        std::vector<int>    b_values;
      };
      

      这种设计的一个好处是向量可以告诉您有多少项目,并且这个概念是可扩展的,以防您需要 6 个项目。

      【讨论】:

      • 虽然最初的问题是关于“可空”浮点数和整数,但我认为这个回答是最好的建议。您可能可以将 2 或 4 个值的处理烘焙到对象模型中并使其干净。如果您允许可以为空的值,那么现在您最多可以打开 16 种可能的组合 (2**4),而实际上您只需要 2 种可能的组合。如果a1 为空,或者a2 为空但b2 不为空,你会怎么做?
      【解决方案4】:

      您有两种选择可以避免boost::optional 从而避免对 Boost 的依赖:

      • 使用编译器的 std::experimental::optional,它可从 GCC 4.9+(以及最新版本 IIRC 中的 Clang)和 -std=c++14 获得。

      • 使用来自 Andrzej Krzemieński 的“参考实现”用于来自 GitHubstd::experimental::optional。它只是标头,所以您可以将标头复制到您的项目中(当然要注意许可证)

      【讨论】:

        【解决方案5】:

        您可以将 NAN 分配给双 a2,这也表明 int b2 无效。

        This page 用于 NAN。

        【讨论】:

        • 这似乎是一个合理的解决方案。 std::numeric_limits&lt;double&gt;::quiet_NaN()std::nan("1") 有什么区别?
        • 我认为 quiet_NaN() 是特定于实现的, std::nan("1") 产生一组特定的位。就您提供的信息而言,这无关紧要,因为无论如何您都应该使用 is_nan() 来检查 NaN。
        • 只是一个警告,您要使用“安静”的 NaN,否则将其设置为 NaN 可能会引发浮点异常。如果你不知道你是否有安静的 NaN,那么你不应该使用 NaN。
        【解决方案6】:
        1. 您可以选择文本文件中不能包含的值(非法值),例如0-1std::numeric_limits&lt;int&gt;::max()。处理数据时,仅使用不等于非法值(或标记)的值。
        2. 包括一个布尔值,指示有多少个值:

          struct A {
              double a1;
              int b1;
              double a2;
              int b2;
              bool has_4_nums;
          };
          
        3. 使用指针(int*std::unique_ptr&lt;int&gt;,根据@Peter Pei Guo),当它们不存在时分配nullptr

        【讨论】:

          【解决方案7】:

          你不能。我可以想到两种替代方法:

          1. 使用int *;或
          2. 使用在您的上下文中肯定无效的值。例如,如果它永远不能为负数,则使用 -1 表示空值。但我还是更喜欢第一种方式,因为它的正确性不取决于需求或上下文。

          【讨论】:

          • @matsjoyce:在您不需要的地方引入动态分配可能是个坏主意,至少对于性能而言。
          • 是的,但是要使用int*,您必须维护所有使用的数字的列表,以使指针保持活动状态。
          【解决方案8】:

          要么你有一个不合法的价值,要么你没有。如果您有一个不合法的值(例如 -1),请将其用作哨兵。如果没有,那么没有。使用Boost.Optional 或滚动您自己的“值加布尔”类。

          【讨论】:

          • 如果你使用非法值作为标记,你应该添加一个断言来检查提供的任何值是否合法。
          猜你喜欢
          • 2020-02-03
          • 2011-05-16
          • 1970-01-01
          • 2015-05-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-09-09
          • 1970-01-01
          相关资源
          最近更新 更多