RAII и неинициализированные ценности - PullRequest
2 голосов
/ 24 апреля 2009

Просто простой вопрос:

если бы у меня был простой векторный класс:

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

Не применимо ли понятие RAII и здесь? то есть предоставить конструктор для инициализации всех значений для некоторых значений (чтобы предотвратить использование неинициализированного значения).

РЕДАКТИРОВАТЬ или предоставить конструктор, который явно просит пользователя инициализировать переменные-члены до того, как объект может быть получен.

1012 * т.е. *

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 ]

6 голосов
/ 24 апреля 2009

"R" в RAII обозначает Ресурс. Не все это ресурс.

Многие классы, такие как std :: vector, самоинициализируются. Вам не нужно беспокоиться об этом.

Типы POD не самоинициализируются, поэтому имеет смысл инициализировать их некоторым полезным значением.

4 голосов
/ 24 апреля 2009

Поскольку поля в вашем классе Vector являются встроенными типами, для обеспечения их инициализации вам придется сделать это в конструкторе:

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

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

Теперь, если ваши поля были классами, которые были написаны правильно, они должны автоматически инициализироваться (и при необходимости очищаться).

В некотором смысле это похоже и связано с RAII в том смысле, что RAII означает, что ресурсы (память, дескрипторы, что угодно) автоматически получают и очищают объект.

3 голосов
/ 24 апреля 2009

Вы используете шаблон RAII, когда вам нужно выполнить явную очистку, и хотите, чтобы эта очистка происходила одновременно с неявной очисткой другого объекта. Это может происходить для выделения / освобождения памяти, входа / выхода критической секции, соединений с базой данных и т. Д. В вашем примере «поплавки» очищаются автоматически, поэтому вам не нужно беспокоиться о них. Однако, скажем, у вас была следующая функция, которую вы вызывали для получения векторов:

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

И, скажем, вызывающая сторона несет ответственность за удаление возвращенного вектора. Если вы назвали этот код следующим образом:

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

Вы должны помнить, чтобы освободить вектор. Если «материал» - это длинный фрагмент кода, который может выдать исключение или содержать несколько операторов return, вам придется освобождать вектор с каждой точкой выхода. Даже если вы это сделаете, тот, кто поддерживает код, добавив еще один оператор «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 и т. Д.

3 голосов
/ 24 апреля 2009

Я бы точно не сказал, что здесь применяется RAII. Запомните, что означают буквы: получение ресурсов - инициализация . Здесь у вас нет ресурсов, поэтому RAII не применяется.

Вы можете предоставить конструктор по умолчанию для Vector; это избавит вас от необходимости явно инициализировать всех членов VectorField. Компилятор вставит код, который сделает это за вас.

0 голосов
/ 24 апреля 2009

Если вы не пишете конструктор, компилятор сгенерирует для вас конструктор по умолчанию и установит эти значения по умолчанию (неинициализированные значения). Предоставьте конструктор по умолчанию самостоятельно и инициализируйте значения, так как это будет лучшим способом сделать это. Я не думаю, что это слишком сложно сделать это. Не ленитесь: -)

...