0

我正在使用一个例程来初始化一个类的聚合成员。

class MyClass
{
public:
    void Init()
    {
        double  array2D[10][10] = {0.0};
        bool    logicalarray[2] = {false};
    }

private:
    double  array2D[10][10];  
    bool    logicalarray[2]; 
};

int main()
{
    MyClass* myClassObject = new  MyClass();
    myClassObject->Init();

    delete myClassObject;
    return 0;
}

这有什么问题吗?它编译、构建和运行良好。在调试时,我确实看到每个数组元素都按照我在 Init() 中定义的方式进行了初始化。但是,代码清理工具报告说,在 Init() 中,已声明命名变量但未引用。

PS:没有 C++11

4

1 回答 1

1

代码清理工具是对的。这段代码没有做你认为它做的事情:

void Init()
    {
        double  array2D[10][10] = {0.0};
        bool    logicalarray[2] = {false};
    }

认为这段代码初始化了MyClass的成员变量。它实际上做的是声明两个本地(自动)变量,初始化它们,然后返回。成员变量没有被触及,并且隐藏Init()'s body 中。

您可以通过以下方式解决此问题:

void Init()
    {
        array2D[10][10] = {0.0};
        logicalarray[2] = {false};
    }

但我认为这在技术上是正确的,但仍然是错误的。您正在使用所谓的两阶段构造。这两个阶段是: 1) 构造一个MyObject. MyObject2)通过调用它的Init()函数来初始化它。

丑陋的。讨厌。容易出错和健忘。语义不正确,因为构造函数不会使对象处于完全初始化状态。作为一般规则,您应该不惜一切代价避免两阶段建设。更好的方法是在对象的构造函数中执行所有初始化 - 最好在成员初始化列表中,但这对于聚合成员来说是困难/不可能的。在这些情况下,在构造函数的主体中初始化:

class MyClass
{
public:
  MyClass ()
  {
    array2D[10][10] = {0.0};
    logicalarray[2] = {false};
  }
  // ...
};

现在, 的构造MyObject也意味着的初始化MyObject毕竟,这就是构造函数的用途。改为这样做。

这里的问题是我们不能像这样初始化聚合。我们只能在构造时使用此语法初始化聚合,但这发生在(不存在的)初始化列表中。我们不能在 C++03 中使用初始化列表来初始化聚合。所以你留下了一个丑陋的情况:

MyClass ()
{
  memset (logicalarray, logicalarray+2, 0);
  memset (array2D, array2D+sizeof (array2D), 0);
}

这导致我提出一个论点,即您不应该首先使用原始数组,而应该使用 a vector(或其他东西)并通过以下方式对其进行初始化:

   class MyClass
    {
    public:
      std::vector <bool> mBools;
      std::vector <std::vector <double> > mDoubles;
      MyClass ()
      {
        std::fill_n (std::back_inserter (mBools), 2, false);
      }
    };

我将把初始化mDoubles作为练习。

于 2013-09-30T14:09:23.857 回答