RAII和未初始化值
只是一个简单的问题:RAII和未初始化值
,如果我有一个简单的载体类:
class Vector
{
public:
float x;
float y;
float z;
};
犯规的RAII的概念应用在这里呢?即提供一个构造函数将所有值初始化为某些值(以防止使用未初始化的值)。
编辑或提供一个构造函数,明确要求用户在实例化对象之前初始化成员变量。
即
class Vector
{
public:
float x;
float y;
float z;
public:
Vector(float x_, float y_, float z_)
: x(x_), y(y_), z(z_)
{ // Code to check pre-condition; }
};
应该RAII被用来帮助程序员忘记使用数据之前初始化值,或者是开发商的责任?
或者是看RAII的错误方式?
我故意让这个例子很简单。我真正的问题是回答,例如,复合材料类,如:
class VectorField
{
public:
Vector top;
Vector bottom;
Vector back;
// a lot more!
};
正如你所看到的......如果我不得不写一个构造函数初始化每一个成员,这是相当繁琐的。
想法?
RAII中的“R”代表资源。并非一切都是资源。
许多类,如std :: vector,都是自我初始化的。你不需要担心这些。
POD类型是而不是自我初始化,因此将它们初始化为一些有用的值是有意义的。
我不会说RAII适用于此。请记住这些字母代表的是:资源获取是初始化。您没有资源被收购,因此RAII不适用。
您可以提供一个默认构造函数Vector
;这将消除您明确初始化VectorField
的所有成员的需要。编译器会插入代码为你做。
由于您Vector
类中的字段是内置的类型,以确保它们被初始化,你将不得不做,在一个构造函数:现在
class Vector
{
public:
float x;
float y;
float z;
Vector() : x(0.0), y(0.0), z(0.0) {}
};
,如果你的领域是类如果它们写得很好,它们应该自动初始化(如果需要的话,自行清理)。
以某种方式,这与RAII类似并且与RAII相关,因为RAII意味着资源(内存,句柄,任何)由对象自动获取和清理。
如果你不写构造函数,编译器会生成一个默认构造你,并设置这些值设置为默认(未初始化值)。提供一个默认的构造函数,并初始化值,这将是您最好的方式来做到这一点。我不认为这样做太复杂。不要太懒惰:-)
当您需要执行显式清理并且希望在清除另一个对象的同时发生清理时,可以使用RAII模式。这可能发生在内存分配/释放,关键部分进入/退出,数据库连接等等。在您的示例中,“浮动”会自动清除,因此您不必担心它们。但是,假设您有以下函数来调用以获取向量:
Vector* getMeAVector() {
Vector *v = new Vector();
// do something
return v;
}
并且说这是调用者的责任,即删除返回的向量。如果您按以下方式调用此代码:
Vector *v = getMeAVector();
// do some stuff with v
delete v;
您必须记住释放该向量。如果“stuff”是一段很长的代码,可能会抛出一个异常,或者在那里有一堆return语句,那么你必须在每个退出点释放vector。即使你这样做了,通过添加另一个“返回”语句或调用某个引发异常的库来维护代码的人可能不会。相反,你可以这样写一个类:
然后,你可以得到向量像这样:
Vector *v = getMeAVector();
AutoVector av(v);
// do lots of complicated stuff including throwing exceptions, multiple returns, etc.
那么你不必担心删除向量了,因为当av超出范围将自动删除。如果需要,您可以编写一个小宏使“AutoVector av(v)”语法更好一些。
这是一个人为的例子,但是如果周围的代码很复杂,或者它可以抛出异常,或者有人在中间添加“return”语句,那么“AutoVector”将自动释放内存。
你可以做同样的事情用一个“自动”级进入其构造函数和出口在其析构函数的一个关键部分,等
如果值是未初始化的,那么我不认为这是恰当的说编译器生成的构造函数具有“将这些值设置为默认值”。它没有把它们设置为任何东西;这就是为什么他们未初始化。 – 2009-04-24 02:56:27