Как обрабатывать неправильные значения в конструкторе?

Я все время использую готовые заявления в Android, это довольно просто:

SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteStatement stmt = db.compileStatement("SELECT * FROM Country WHERE code = ?");
stmt.bindString(1, "US");
stmt.execute();
23
задан Andy 3 February 2010 в 16:13
поделиться

11 ответов

Типичным решением является исключение.

Логика заключается в следующем: конструктор - это метод, который преобразует кусок памяти в допустимый объект. Либо это удается (обычно завершается), и у вас есть действующий объект, либо вам нужен какой-то неузнаваемый индикатор проблемы. Исключения - единственный способ сделать проблему невосполнимой в C ++.

38
ответ дан sharptooth 3 February 2010 в 16:13
поделиться

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

Создайте фабричную функцию, которая создает экземпляр вашего класса в куче, и возвращает нулевой указатель, если создание не удается.

Это не совсем подходит для объектов типа ценностей в качестве дат, но могут быть полезны приложения.

11
ответ дан Timbo 3 February 2010 в 16:13
поделиться

«Исключение, выброшенное из C'Tor» - это не слово из четырех букв. Если объект не может быть создан правильно, C'tor должен потерпеть неудачу, потому что вы скорее отказали бы в создании, чем имели бы недопустимый объект.

5
ответ дан Gal Goldman 3 February 2010 в 16:13
поделиться

Обычно для создания объекта Time у вас есть закрытый / защищенный конструктор и открытый статический метод фабрики. Не следует генерировать исключение из конструктора, потому что это наносит ущерб наследованию. Таким образом, ваш фабричный метод может выдать исключение, если это необходимо.

3
ответ дан 3 February 2010 в 16:13
поделиться

Еще одна альтернатива для полноты:

  • Перепроектировать интерфейс так, чтобы недопустимые значения были «невозможны»

Например, в своем классе «Время» вы могли бы иметь:

class Time{
public:
    Time(Hours h, Minutes m, Seconds s);
//...
};

Часы, минуты и секунды являются ограниченными значениями. Например, с помощью (еще не) библиотеки Boost Constrained Value:

typedef bounded_int<unsigned int, 0, 23>::type Hours;
typedef bounded_int<unsigned int, 0, 59>::type Minutes;
typedef bounded_int<unsigned int, 0, 59>::type Seconds;
31
ответ дан Éric Malenfant 3 February 2010 в 16:13
поделиться

Рассмотрим фабричный шаблон для генерации объектов времени:

static bool Time::CreateTime(int hour, int min, int second, Time *time) {
  if (hour <= 12 && hour >= 0 && min < 60 && min >= 0 && 
      second < 60 && second >= 0)  {
     Time t(hour, min, second);
     *time = t;
     return true;
  }
  printf("Your sense of time seems to be off");
  return false;
}

Time t;
if (Time::CreateTime(6, 30, 34, &t)) {
  t.time(); // :)
} else {
  printf("Oh noes!");
  return;
}

Это делает предположение, что Time имеет:

  • конструктор по умолчанию
  • a конструктор копирования
  • оператор присваивания копии
-1
ответ дан ascotan 3 February 2010 в 16:13
поделиться

Первый - лучший, исключения - лучший способ сообщить пользователям класса об ошибках.

это не рекомендуется другим способом, потому что если конструктор возвращается без ошибок, это означает, что вы правильно сконструировали объект и можете использовать его где угодно

1
ответ дан Ahmed Said 3 February 2010 в 16:13
поделиться

Просто, чтобы подробнее остановиться на ответах, данных onebyone и Timbo . Когда люди обсуждают использование исключений, обычно кто-то в конечном итоге говорит: «Исключения следует использовать в исключительных ситуациях».

Как вы можете видеть из большинства ответов здесь, если конструктор дает сбой, тогда правильный ответ бросить исключение. Однако, в вашем случае, это не обязательно, что вы не можете создать объект, более того, вы не хотите, чтобы его создал.

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

Лично я склонялся бы к проверке аргументов перед построением объекта времени (что-то вроде ответа Тимбо ), и тогда я бы имел утверждение в конструкторе, чтобы проверить, что их аргументы действительны.

В том случае, если вашему конструктору нужен ресурс (например, выделяет память), то это, ИМХО, будет ближе к исключительной ситуации, и тогда вы выдадите исключение.

1
ответ дан Community 3 February 2010 в 16:13
поделиться

Я не думаю, что у вас есть большой выбор.

Если вы получили неверный ввод, вы не можете сделать больше, чем сообщить вызывающему, чем он является недействительным. Затем вы можете использовать код исключения или ошибки.

Код ошибки в конструкторе необходимо будет передать в качестве ссылочного параметра, и поэтому он будет выглядеть очень неудобно.

Вы можете попытаться найти способ проверить входные данные в источнике. Почему вы получаете неверные данные? Как ввод может быть недействительным и т. Д.

Примером для вашего класса дат будет принуждение пользователя (пользователя вашей программы) вводить только действительную дату (заставляя его вводить ее в виде календаря). GUI, например).

Вы также можете попытаться создать метод в своем классе для обработки проверки ввода.

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

Если производительность важна, и вы не хотите вызывать функцию validate дважды (пользователь вызывает ее, затем в конструкторе), я думаю, вы могли бы использовать именованный конструктор idiom, чтобы иметь CheckedConstructor и UncheckedConstructor.

Это начинает переусердствовать в архитектуре, хотя, я думаю.

В конце концов, это будет зависеть от класса и варианта использования.

1
ответ дан n1ckp 3 February 2010 в 16:13
поделиться

Обычно я бы сказал (1). Но если вы обнаружите, что все вызывающие объекты окружают конструкцию с помощью try / catch, вы можете также предоставить статическую вспомогательную функцию в (3), так как с небольшой подготовкой исключение может быть сделано невозможным.

Существует еще один вариант, хотя он имеет существенные последствия для стиля кодирования, поэтому его не следует воспринимать легкомысленно,

5) Не передавайте параметры в конструктор:

class Time
{
protected:
    unsigned int m_hour;
    unsigned int m_minute;
    unsigned int m_second;
public:
    Time() : m_hour(0), m_minute(0), m_second(0) {}
    // either return success/failure, or return void but throw on error,
    // depending on why the exception in constructor was undesirable.
    bool Set(unsigned int hour, unsigned int minute, unsigned int second);
};

Это называется двухфазным построением и используется именно в ситуациях, когда конструкторам нежелательно или невозможно генерировать исключения. Код с использованием nothrow new, который должен быть скомпилирован с помощью -fno-exceptions, вероятно, является классическим случаем Как только вы привыкаете к этому, это немного менее раздражает, чем вы могли подумать.

12
ответ дан Steve Jessop 3 February 2010 в 16:13
поделиться
  • имеют конструктор, который выдает исключение, и имеют обработчики в вызывающей функции для его обработки.

Да. Разработать по контракту и оставить предварительную проверку включенной, а в случае неудачи вывести исключение. Нет больше недействительных раз.

  • имеют флаг в классе и устанавливают его в true, только если значения приемлемы для конструктора, и программа проверяет флаг сразу после построения.

Может быть. Приемлемо в сложных случаях, но опять же, бросить, если проверка не удалась.

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

Может быть. Речь идет о том, чтобы сказать, верны ли входные данные, или нет, и может быть полезно, если сказать, что это нетривиально, но см. Выше для , как реагировать в случае неверных данных.

  • переработать класс так, чтобы он мог быть построен из любых входных параметров.

Нет. Вы в основном отложите проблему.

3
ответ дан Community 3 February 2010 в 16:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: