RAII和未初始化的值

时间:2009-04-24 02:38:23

标签: c++ 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!
};

正如你所看到的......如果我必须编写一个构造函数来初始化每个成员,那就非常繁琐了。

思想?

5 个答案:

答案 0 :(得分:6)

RAII中的“R”代表资源。并非一切都是资源。

许多类,例如std :: vector,都是自我初始化的。你不必担心这些。

POD类型自我初始化,因此将它们初始化为一些有用的值是有意义的。

答案 1 :(得分:4)

由于Vector类中的字段是内置类型,为了确保它们已初始化,您必须在构造函数中执行此操作:

class Vector
{
public:
  float x;
  float y;
  float z;

  Vector() : x(0.0), y( 0.0), z( 0.0) {}
};

现在,如果您的字段是正确编写的类,则它们应自动初始化(并在必要时进行清理)。

在某种程度上,这与RAII相似,因为RAII意味着对象可以自动获取和清理资源(内存,句柄等)。

答案 2 :(得分:3)

我不确切地说RAII适用于此。记住字母代表的含义:资源获取是初始化。您没有在此获得资源,因此RAII不适用。

您可以为Vector提供默认构造函数;这将使您无需显式初始化VectorField的所有成员。编译器会插入代码来为您执行此操作。

答案 3 :(得分:3)

当您需要进行显式清理时,可以使用RAII模式,并希望在清除另一个对象的同时进行清理。对于内存分配/释放,关键部分进入/退出,数据库连接等,可能会发生这种情况。在您的示例中,“浮动”会自动清除,因此您无需担心它们。但是,假设您调用了以下函数来获取向量:

Vector* getMeAVector() {
    Vector *v = new Vector();
    // do something
    return v;
}

并说调用者有责任删除返回的向量。如果您通过以下方式调用此代码:

Vector *v = getMeAVector();
// do some stuff with v
delete v;

你必须记住释放矢量。如果“stuff”是一长串代码,可能会抛出异常,或者在那里有一堆返回语句,那么你必须在每个出口点释放向量。即使你这样做,通过添加另一个“return”语句或调用某个抛出异常的库来维护代码的人也许不会。相反,你可以写一个这样的类:

class AutoVector
{
        Vector *v_;
    public:
        AutoVector(Vector *v) : v_(v) {}
        ~AutoVector() { delete v_; }
};

然后,您可以像这样获得矢量:

Vector *v = getMeAVector();
AutoVector av(v);
// do lots of complicated stuff including throwing exceptions, multiple returns, etc.

然后您不必再担心删除矢量了,因为当av超出范围时,它将被自动删除。如果需要,你可以编写一个小宏来使“AutoVector av(v)”语法更好一些。

这是一个人为的例子,但是如果周围的代码很复杂,或者它可以抛出异常,或者有人出现并在中间添加“返回”语句,那么“AutoVector”将会很好自动释放内存。

您可以使用“自动”类进行同样的操作,该类进入其ctor中的关键部分并退出其dtor等。

答案 4 :(得分:0)

如果您不编写构造函数,编译器将生成 默认构造函数,并将这些值设置为默认值(未初始化的值)。自己提供默认构造函数并初始化值,这将是您最好的方法。我不认为这样做太复杂了。不要太懒: - )