Нулевой шаблон с QObject

(C++/Qt) У меня есть умный указатель на QObject. Скажем, QWeakPointer. По какой-то внешней причине (что-то, что может произойти в другом объекте или из-за события) возможно, что указанный объект будет уничтожен. Поскольку у меня есть умный указатель, не будет оборванной ссылки, так что проблем нет. Но мне всегда нужно проверять, является ли указатель нулевым или нет.

Я думаю об использовании нулевого шаблона, чтобы не проверять это все время, но я не уверен, возможно ли это или удобно с QObject. Идея заключалась бы в том, что указатель указывает на объект, и в случае его уничтожения интеллектуальный указатель меняет свой указанный объект на нулевой объект. Это хорошая идея или я должен забыть об этом и просто проверять, всегда ли указатель равен NULL?


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

class Worker : public QObject
{
    Q_OBJECT

public:
    Worker(QObject *parent = 0);
    void work()
    {
        if(m_tool)
            m_tool->use();
        emit workCompleted();
    };

signals:
    workCompleted();

public slots:
    void setTool(QWeakPointer<Tool> tool);

private:
    QWeakPointer<Tool> m_tool;
};


class Tool : public QObject
{
    Q_OBJECT

public:
    Tool();

public slots:
    void use() =0;
};


class Screwdriver : public Tool
{
    Q_OBJECT

public:
    Screwdriver() : Tool();

public slots:
    void use()
    {
        // do something
    };
};


class Hammer : public Tool;
class Saw : public Tool;
...

В данном случае Инструмент является общедоступным объектом библиотеки, который используется Работником. Я разрабатываю такую ​​библиотеку. Итак, рабочий использует отвертку, но она ломается и уничтожается. Без проблем:

if(m_tool)
    m_tool->use();
emit workCompleted();

m_tool равен 0, поэтому он просто ничего не делает. Но мы должны каждый раз проверять, что это не null.

Теперь предположим, что у нас есть объект NullTool:

class NullTool : public Tool
{
    Q_OBJECT

public:
    NullTool() : Tool();

public slots:
    void use()
    {
        // does nothing
    };
};

Когда инструмент будет уничтожен, наш указатель будет умным и будет знать, что он должен указывать на экземпляр NullTool. Таким образом, Worker::work() может быть реализован следующим образом:

void Worker::work()
{
    m_tool->use();
    emit workCompleted();
};

Затем m_tool->use() будет вызываться для NullTool, который ничего не делает, поэтому не нужно будет проверять, что указатель не равен нулю.

Это хорошая идея? Возможно ли это с помощью классов интеллектуальных указателей, предоставляемых Qt, или мне следует создать подкласс QWeakPointer?


person user427569    schedule 31.08.2010    source источник
comment
Я не вижу никаких проблем с проверкой того, является ли m_tool нулевым. Что вас беспокоит?   -  person tibur    schedule 31.08.2010


Ответы (3)


Я думаю, что шаблон нулевого объекта имеет смысл для классов, подобных значениям. Примерами являются QString или QVariant, если вы не хотите иметь такой код, как if (str && !str->isEmpty()), а просто делаете if (!str.isEmpty()). Для QObjects, которые не являются значениями, но имеют «идентификацию», я никогда не находил это полезным.

person Frank Osterfeld    schedule 31.08.2010

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

void destroyed ( QObject * obj = 0 );
person tibur    schedule 31.08.2010

Я не вижу никакой проблемы в вашей идее. Вам просто нужно сравнить работу, которая требуется для его реализации, с работой по проверке указателя каждый раз. Давайте проверим указатель 10 000 раз, это хорошая идея, чтобы использовать ваш подход. Примечание. Шаблон нулевого объекта основан на том факте, что Tool::use() не имеет никаких побочных эффектов.

Позаботьтесь о том, чтобы возможные побочные эффекты в Tool::use() не мешали, когда вы заменяете его полиморфно на NullTool::use(). Другими словами: убедитесь, что вы не нарушаете принцип замены Лисков.

person WolfgangP    schedule 05.09.2010