нулевые проверки не требуются для const unique_ptr, возвращенного фабричным методом? - PullRequest
2 голосов
/ 05 апреля 2019

У нас есть много существующего кода, использующего необработанные указатели, которые заполнены нулевыми проверками почти при каждом использовании.

Пытаясь писать более новый код более аккуратно, мы пытаемся использовать методы конструктора фабрики и unique_ptrs.

Мой вопрос в приведенном ниже коде, как только мы получим наш фабрично созданный объект - sensorX - можем ли мы использовать его в остальной части кода без дальнейших нулевых проверок, поскольку это const unique_ptr?

DeviceFactory.h

class DeviceFactory
{
public:

    template<typename T>
    static unique_ptr<T> create(int id, std::string status)
    {
        auto device = unique_ptr<T>{ new T{ id, status } };

        if (!device) throw DeviceCreationException("device couldn't be created");

        return device;
    }
};

Использование

const auto sensorX = DeviceFactory::create<Sensor>(123, "sensorX");

Ответы [ 5 ]

2 голосов
/ 05 апреля 2019

Похоже, вы написали свою собственную версию std::make_unique с менее гибким API.Я бы порекомендовал настроить API, поскольку это облегчит обновление.

Тем не менее, ваш вопрос касается проверки на нуль.Как указывалось несколько раз в комментариях, вам не нужно проверять после получения указателя, так как нужно бросить std :: bad_alloc.Тем не менее, давайте предположим, что у вас есть еще одна проверка, которая выдает такое пользовательское исключение, а не главный вопрос: каков ваш API, включая условия до и после.

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

Моя привычка состояла бы в том, чтобы утверждать указатель перед использованием или после создания.Однако вы можете автоматизировать эту работу, используя дезинфицирующие средства Clang / Gcc.GSL также имеет доступную проверку для этого использования nullptr.

Мое предложение: утверждать после создания переменной (или использовать дезинфицирующие средства), которая должна найти ошибку во время тестирования, если пост-условия изменятся.Находясь вместе со своими колледжами, вы должны согласиться с тем, что не допускается, чтобы unique_ptr содержал null, если не задокументировано, что представляет собой nullptr.

1 голос
/ 05 апреля 2019

Вы можете сделать это, даже если это не const unique_ptr, при условии, что вы никогда не сбросите его на ноль.

В заводской функции

        auto device = unique_ptr<T>{ new T{ id, status } };
        if (!device) throw DeviceCreationException("device couldn't be created");

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

1 голос
/ 05 апреля 2019

Прежде всего, проверка:

if (!device) throw DeviceCreationException("device couldn't be created");

не имеет особого смысла, потому что в то время, когда это условие if будет достигнуто, для device будет невозможно nullptr(по крайней мере, не для данного кода)

С точки зрения пользователя, известно, что функция возвращает unique_ptr из-за подписи, но вам необходимо прочитать документацию, если DeviceFactory::create<Sensor> вызов гарантирует, что он не содержит nullptr.И даже если документация это гарантирует, все же может быть хорошей идеей проверить это самостоятельно, потому что вы не знаете, что так будет всегда в будущем.

Так что вопрос в том, всегда ли высохраните его как const unique_ptr, тогда зачем вам вообще указатель, вместо того, чтобы писать:

template<typename T>
static T create(int id, std::string status)
{
    auto device = T{ id, status };

    return device;
}

Но вернемся к вашему вопросу.Если const auto sensorX = ... инициализируется с unique_ptr, который не содержит nullptr, то гарантируется, что он не будет nullptr в течение срока службы.

1 голос
/ 05 апреля 2019

A unique_ptr все еще может быть nullptr, это просто означает, что этот объект обрабатывает базовый ресурс, а не то, что есть приобретенный ресурс.

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

Примечание: что запрещает кому-либо называть вашу фабрику и не сохранять результат в unique_ptr?Пока это разрешено, вам придется проверять.

0 голосов
/ 05 апреля 2019

как только мы получим наш фабрично созданный объект - sensorX - можем ли мы использовать его в остальной части кода без дальнейших нулевых проверок на нем?

Как указали другие ответы, ответ - нет".Но то, что вы можете сделать, это использовать шаблон owner<> ( реализация MS ), , описанный в рекомендациях:

  • OneВы установили, что (необработанный) указатель имеет ненулевое значение, оберните его в owner<T*>;
  • У методов есть owner<T*> вместо T* в качестве параметров

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

...