我正在使用例程来初始化类的聚合成员。
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
答案 0 :(得分:1)
代码清理工具是对的。此代码不符合您的想法:
void Init()
{
double array2D[10][10] = {0.0};
bool logicalarray[2] = {false};
}
您认为此代码初始化MyClass
的成员变量。它实际上做的是声明两个本地(自动)变量,初始化它们,然后返回。不会触及成员变量,并且Init()
的{{1}}内部是hidden。
您可以通过以下方式解决此问题:
void Init()
{
array2D[10][10] = {0.0};
logicalarray[2] = {false};
}
但我认为这在技术上是正确的,但仍然是错误的。您正在使用所谓的两阶段构造。这两个阶段是:1)构建MyObject
。 2)通过调用MyObject
函数初始化Init()
。
难看。讨厌。容易出错和错误forgetfullness。语义错误,因为构造函数不使对象处于完全初始化状态。作为一般规则,您应该不惜一切代价避免两阶段建设。更好的方法是在对象的构造函数中执行所有初始化 - 最好是在成员初始化列表中,但这对于聚合成员来说很难/不可能。在这些情况下,在构造函数体中初始化:
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);
}
这引出了一个争论,你不应该首先使用原始数组,而是使用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
的初始化作为练习。