Конструктор может возвратить Нулевое значение?

Я знаю, что конструкторы не "возвращают" ничего, но например если я звоню CMyClass *object = new CMyClass() там какой-либо путь состоит в том, чтобы сделать объект быть ПУСТЫМ, если конструктор перестал работать? В моем случае у меня есть некоторые изображения, которые должны быть загружены и если бы чтение файла перестало работать, я хотел бы, чтобы это возвратило пустой указатель. Там какой-либо путь состоит в том, чтобы сделать это?
Заранее спасибо.

30
задан Sanctus2099 16 August 2018 в 07:20
поделиться

12 ответов

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

static CMyClass* CMyClass::create();

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

27
ответ дан 27 November 2019 в 23:32
поделиться

Лучше всего делать исключения.

Вы также можете проверить значение errno , если вы программируете в среде Unix.

0
ответ дан 27 November 2019 в 23:32
поделиться

В Visual C ++ 6 поведение по умолчанию при нехватке памяти заключалось в том, что оператор new возвращал NULL, а не генерировал исключение. Это не было поведением, стандартизованным позже в C ++, и не было идиоматическим в современном C ++.

Но вы, конечно, можете создать версию оператора new, которая ведет себя таким образом, если хотите, или использовать вариант nothrow : if (Foo * foo = new (std :: nothrow ) Фу) {...} .

0
ответ дан 27 November 2019 в 23:32
поделиться

Вы можете использовать malloc вместо new , поскольку malloc не генерирует исключения. Вам нужно будет проверить результат malloc , прежде чем использовать указатель. Кроме того, если malloc завершится успешно, вам придется инициализировать объект.

Предупреждение:

malloc не вызывает конструктор объекта.

0
ответ дан 27 November 2019 в 23:32
поделиться

Можно ли вместо этого использовать статический фабричный метод? При преобразовании между типами я мог бы сделать общедоступный статический CMyClass Convert (оригинал) и вернуть null, если оригинал равен нулю. Однако вы, вероятно, все равно захотите генерировать исключения для недопустимых данных.

3
ответ дан 27 November 2019 в 23:32
поделиться

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

Обратите внимание, что конструктор не выполняет никакого управления памятью. Память выделяется извне, а затем вызывается конструктор для ее инициализации. И эта память может быть выделена динамически ( тип * x = новый тип; ), но она также может быть в стеке ( тип x; ) или подобъектом более сложного типа. . Во всех случаях, кроме первого, значение null вообще не имеет смысла.

22
ответ дан 27 November 2019 в 23:32
поделиться

Безвкусица.

Что ж, если вы действительно хотите это сделать, перегрузите new, вызовите new частный конструктор, который не выполняет инициализацию, выполните инициализацию в new и верните new null, если инициализация не удалась.

1
ответ дан 27 November 2019 в 23:32
поделиться

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

-3
ответ дан 27 November 2019 в 23:32
поделиться

Фактически вы можете заставить new "возвращать" 0, используя std :: nothrow, но это только приводит к тому, что он возвращает 0, если выделение памяти не удается. Как только он дошел до вашего конструктора, вы уже не сможете получить то, что хотите.

Вы должны разделить проблемы в вашем классе. Конструктор почти никогда не должен (я хочу сказать, что период «никогда», но я оставлю место для редкого исключения, о котором не могу придумать) обрабатывать файлы, если только обработка файлов не является его исключительной ответственностью (например, fstream).

0
ответ дан 27 November 2019 в 23:32
поделиться

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

Вот как это сделать: У вас уже есть конструктор, который берет путь к файлу и загружает его, бросая на сбой. Переместите внутренности в метод Load, который принимает путь к файлу и возвращает bool, чтобы указать на успех.Затем измените конструктор так, чтобы он просто вызывает Load и выдает false. В поле Load убедитесь, что экземпляр немедленно возвращает значение false, если экземпляр правильно инициализирован. Затем добавьте деструктор по умолчанию и метод IsValid.

Пер Деннис: Теперь добавьте второй конструктор, который принимает логическое значение для управления возникновением исключения, и рассмотрите возможность понижения Load до private, и в этом случае вы также удалите конструктор по умолчанию.

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

// Per Dennis, should go away if Load becomes private.
Image()
{
    _valid = false;
}

Image(const string& filepath)
{
    if (!Load(filepath))
        throw new exception("Cannot open image.");
}

// Per Dennis.
Image(const string& filepath, bool doThrow)
{
    if (!Load(filepath) && doThrow)
        throw new exception("Cannot open image.");
}

// Per Dennis, this should probably be made private now.
bool Load(const string& filepath)
{
    if (_valid)
        return false;

    // Try to load...
    _valid = WhetherItLoadedExpression;
    return _valid;
}

bool IsValid()
{
    return _valid;
}

void Draw()
{
    if (!IsValid())
        throw new exception("Invalid object.");

    // Draw...
}

edit

См. ниже изменения, сделанные в ответ на комментарий Денниса.

1
ответ дан 27 November 2019 в 23:32
поделиться

Способ сделать это заключается в том, что если вы обнаружите, что что-то не работает в вашем конструкторе, вы должны выбросить исключение. Вот что происходит, если C++ не может выделить память для вашего объекта - он выбрасывает std::bad_alloc. Вы должны использовать std::exception или его подкласс.

6
ответ дан 27 November 2019 в 23:32
поделиться

"Правильный "** способ - выбросить исключение.

** Вы можете предоставить функцию-член типа is_valid, которую можно проверить после конструирования объекта, но это просто не идиоматично в C++.

9
ответ дан 27 November 2019 в 23:32
поделиться
Другие вопросы по тегам:

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