На сколько плохо такое решение?

136
30 ноября 2019, 19:00

Есть функция сравнивающая два объекта и фиксирующая что именно различается в объектах. В словаре хранятся типы изменений и указатели на метод свойства объекта. До этого была конструкция из if`ов. Но мне кажется что такой подход слишком сложен для понимания. Как еще можно сравнить два объекта на различия.

UserEventList MonAdmin::compareObjects(const MonObject &oldObject, 
                                       const MonObject &newObject)
   {
        UserEventList list;
        QMap<UserEvent::EventType, QString (MonObject::*)() const> map;
        map.insert(UserEvent::ChangeName, &MonObject::name);
        map.insert(UserEvent::ChangeParent, &MonObject::parentToString);
        map.insert(UserEvent::ChangeSim, &MonObject::simNumber);
        map.insert(UserEvent::ChangeUid, &MonObject::uid);
        map.insert(UserEvent::ChangeClient, &MonObject::clientName);
        map.insert(UserEvent::ChangeDeviceName, &MonObject::deviceName);
        map.insert(UserEvent::ChangeDeviceSerial, &MonObject::deviceSerial);
        map.insert(UserEvent::ChangeAutoProfile, &MonObject::autoProfileToString);
        map.insert(UserEvent::ChangeConfiguration, &MonObject::configToString);
        QMapIterator<UserEvent::EventType, QString (MonObject::*)() const> it(map);
        while (it.hasNext()) {
            it.next();
            QString oldValue = (oldObject.*(it.value()))();
            QString newValue = (newObject.*(it.value()))();
            if (oldValue != newValue) {
                UserEvent event;
                event._type = it.key();
                event._oldValue = oldValue;
                event._newValue = newValue;
                list.append(event);
            }
        }
        return list;
    }
Answer 1

Такое решение читается лучше чем цепочка if-ов, потому что компактнее.

Однако, есть и недостатки: (1) большое число аллокаций памяти на куче (в map.insert), которые делаются при каждом сравнении, и которых вообще небыло в реализации через if. (2) Обход map-а через итераторы, имеет оверхед, в сравнении даже с обходом массива. При этом ассоциативность контейнера map не используется никак. (3) Использование сложносочиненных шаблонных типов (например QMapIterator<UserEvent::EventType, QString (MonObject::*)() const>), не облегчает чтение. (4) В отличии от от варианта с if, добавить поле, типа int, окажется сложно. (Нужен переход на QVariant, или аналоги).

Эти недостатки можно исправить:

Введем отдельный тип для геттеров.

typedef QString (MonObject::*t_MonObject_getter)() const;

Вместо локального объекта map, ввел бы статический массив MonObject_meta_info

struct {
    UserEvent::EventType eventType;
    t_MonObject_getter   getter;
} static const MonObject_meta_info[] =
{
    { UserEvent::ChangeName  , &MonObject::name            },
    { UserEvent::ChangeParent, &MonObject::parentToString  },
    ...
};

(Вместо анонимной структуры можно использовать именованную структуру или std::pair, в зависимости от принятого code-style.) Этот массив инициализируется единожды, на этапе старта программы, и расположен в памяти непрерывно, что удешевляет итерирование по нему, и позволяет копилятору вообще развернуть цикл.

Цикл обхода массива MonObject_meta_info читается лучше всего, если записан без явных итераторов или индексов:

for( auto& it: MonObject_meta_info )
{
        QString oldValue = (oldObject.*(it.getter))();
        QString newValue = (newObject.*(it.getter))();
        if (oldValue != newValue) {
            UserEvent event;
            event._type = it.eventType;
            event._oldValue = oldValue;
            event._newValue = newValue;
            list.append(event);
        }            
}

Недостаток (4) не праоделим, без существенного усложнения кода, что оправдано только если имеется большое число объектов (или полей) для которых нужно производить подобное сравнение.

READ ALSO
Как отключить оптимизацию copy elision?

Как отключить оптимизацию copy elision?

Ситуация заключается в том, что не могу отключить copy elisionВ проекте присутствуют конструкторы с глобальными побочными эффектами

134
Visual Studio Code Компиляция многофайлового проекта

Visual Studio Code Компиляция многофайлового проекта

Каким образом в Visual Studio Code можно организовать компиляцию многофайлового проектаК примеру имеется 3 файла: main

124
C++ Variadic templates

C++ Variadic templates

Здравствуйте есть следующий класс, со следующей реализацией:

120
Поиск заданной области в окне

Поиск заданной области в окне

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

109