2

只是一个简单的问题:

如果我有一个简单的向量类:

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

RAII 概念在这里也适用吗?即提供一个构造函数来将所有值初始化为某些值(以防止使用未初始化的值)。

编辑或提供一个构造函数,该构造函数明确要求用户在对象可以被实例化之前初始化成员变量。

IE

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!
};

正如你所看到的......如果我必须编写一个构造函数来初始化每个成员,那是相当乏味的。

想法?

4

5 回答 5

6

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

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

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

于 2009-04-24T02:46:15.980 回答
4

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

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

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

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

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

于 2009-04-24T02:46:58.413 回答
3

我不会说 RAII 在这里适用。记住这些字母代表什么:资源获取是初始化。您在这里没有获得任何资源,因此 RAII 不适用。

您可以为Vector;提供一个默认构造函数。这将消除您显式初始化VectorField. 编译器会插入代码为您执行此操作。

于 2009-04-24T02:46:57.900 回答
3

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

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

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

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

您必须记住释放向量。如果“东西”是一段很长的代码,可能会引发异常,或者其中有一堆返回语句,那么您必须在每个退出点释放向量。即使你这样做了,通过添加另一个“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)”语法更好一些。

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

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

于 2009-04-24T03:02:00.297 回答
0

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

于 2009-04-24T02:48:36.693 回答