指示双值尚未初始化的最佳方法是什么?

时间:2011-10-25 17:47:44

标签: c++ null

我有一个CS类,用于表示3D中的坐标系,即(x,y,z)

class CS
{
  private:
        double x;
        double y;
        double z;
}

CS::CS()
{
   x = NULL;//this causes x = 0//i want the address of x to be 0x000000 & not x = 0
   y = NULL;
   z = NULL:
}

我希望用户可以创建CS(0,0,0)。 在构造函数中,我想初始化x,y和amp;的地址。 z为NULL。 这是为了区分用户定义的(0,0,0)和&默认值。 我正在动态创建CS的对象,因此使用以下代码时有没有点:

class CS
{
  private:
        double *x;
        double *y;
        double *z;
}

CS:CS()
{
    x = new double;
    x = NULL;
    //same for y & z
}

首先,我希望 手动将0x000000地址 分配给任何变量(int或double或char),而不使用指针。 有什么建议吗?

9 个答案:

答案 0 :(得分:13)

您不能将x,y和z的位置更改为NULL,因为位置始终是从CS对象偏移的。它们将永远存在。并不是CSx就像你有车一样,就像CS有一个x就像你有一个头。你不能有头脑。如果它们是整数,你将不得不使它们成为指针(就像你说你不想做的那样),因为这将是从初始化中告知未初始化的唯一方法。但是,double具有很少使用的魔术值:

CS:CS()
: x(std::numeric_limits<double>::quiet_NaN())
: y(std::numeric_limits<double>::quiet_NaN())
: z(std::numeric_limits<double>::quiet_NaN())
{ }

用户可能不会将x,y和z设置为(非一个数字)。

答案 1 :(得分:4)

  

首先,我想在不使用指针的情况下手动为任何变量(int或double或char)分配0x000000地址。有什么建议吗?

这不是你想要的。您想要的是检测变量是否已设置的能力。

其他人建议使用特定的浮点值来检测未初始化状态,但我建议使用Boost.Optional。考虑:

class CS
{
  private:
    boost::optional<double> x;
    boost::optional<double> y;
    boost::optional<double> z;
}

boost::optional可以存储您为模板参数提供的类型,也可以不存储任何内容。您可以使用简单的布尔测试来测试差异:

if(x)
{
  //Has data
}
else
{
  //Has not been initialized
}

缺点是访问数据有点复杂:

x = 5.0; //Initialize the value. x now has data.
y = 4.0 * x; //Fails. x is not a double; it is an optional<double>.
y = 4.0 * (*x); //Compiles, but only works at runtime if x has a value.

答案 2 :(得分:2)

您有几种选择:

  1. 使用指针。
  2. 在每个变量旁边使用布尔标志,指示变量是否已设置。
  3. 如果允许值范围有限,您可以使用特殊值代表“未设置”。对于double,非数字通常是一个自然的候选者。对于intchar,选择一个好的价值通常会更棘手。
  4. 这些选项中没有一个比其他两个选项更好,因为它们涉及不同的权衡。随便挑选。

答案 3 :(得分:2)

如果没有哨兵,你不能用相同的比特数代表它。如果0是有效数字,则无法使用它。如果你尝试将null处理强制转换为值类型,那么你将拥有根本不正确且不可维护的代码。

正确处理空值时,您会看到如下界面:

struct foo {
  virtual ~foo() {}
  virtual bool getX(double &val) = 0;
  virtual bool getY(double &val) = 0;
  virtual bool getZ(double &val) = 0;
};

实现可以有一个在访问之前检查的标志。

void some_func(foo *f) {
  double x, y, z;
  if (f->getX(x) && f->getY(y) && f->getZ(z)) {
    cout << x << ", " << y << ", " << z << endl;
  } else {
    throw std::logic_error("expected some values here");
  }
}

您不想使用无效值而不知道它。必须检查返回值显然是乏味的,但它给你最大的控制。如果它们无效,你也可以使用帮助器或重载。

struct bar {
  double getX() {
    if (!valid)
      throw std::logic_error("bar is not valid");
    return x;
  }
  bool valid;
  double x, y, z; 
}

对我来说,foobar之间的区别在于处理数据的低级代码不应强制执行数据是否存在的策略。在更高的抽象级别,您可以并且应该期望在您使用它时数据是否有效。两者都可以存在于系统中,但foo是必需的。

答案 4 :(得分:2)

为什么你不能简单地这样做:

class CS
{
public:
    // Constructs a CS initialized to 0, 0, 0
    CS() : x(0), y(0), z(0), is_initialized(false) {}

    // User defined values
    CS(double newX, double newY, double newZ) : x(newX), y(newY), z(newZ), is_initialized(true) {}

private:
    double x;
    double y;
    double z;

    // If you need to know that this was initialized a certain way, you could use this suggestion from the comments:
    bool is_initialized;
}

答案 5 :(得分:2)

获取所需内容的语法的一种方法是使坐标的数据类型为带有指示是否已分配的值的类型。这样的事情。

template<typename T>
class CoordinateValue {
   public:
       CoordinateValue() : uninitialized(true), val(0) {}
       CoordinateValue(T x) : uninitialized(false), val(x) {}
       void setVal(T x) {val = x; uninitialized= false}
       // Trivial getters
    private:
       T val;
       bool uninitialized;
};

除非记忆因某种原因而非常缺乏,否则我更喜欢这样的方法。

如果坐标都是默认坐标或全部设置,则可以使用单个标志而不是包含该标志的坐标数据类型。

答案 6 :(得分:2)

如果我理解正确,您希望能够区分无效的默认构造的CS和值为(0.0, 0.0, 0.0)的有效CS。这正是boost::optional http://www.boost.org/doc/libs/1_47_0/libs/optional/doc/html/index.html的用途。

答案 7 :(得分:1)

  

我希望用户可以创建CS(0,0,0)。在构造函数中   想要初始化x,y和amp;的地址z为NULL。这是为了   区分用户定义的(0,0,0)&amp;默认值。   我正在动态创建CS的对象,所以没有意义   使用以下代码:

这就是问题所在。首先,默认值?什么默认值?为什么要有默认值?那是错的。其次,根本不可能改变任何变量的地址。

你想做什么是不可能的,即使可能,也是一个可怕的坏主意。

答案 8 :(得分:0)

您无法更改变量的地址。并且您不能将指针值(如{C ++中的NULLnullptr)分配给非指针类型的变量,例如double