forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   C++ (http://forum.boolean.name/forumdisplay.php?f=22)
-   -   Описатели (Descriptors) (http://forum.boolean.name/showthread.php?t=12707)

HolyDel 23.06.2010 11:25

Описатели (Descriptors)
 
в своем движке применяю такую технику - объекты (движОк, текстура, окно, шрифт) создаются не через параметры, например:
Код:

Texture *tex = eng->LoadTexture("somefile.jpg",TF_ANISOTROPIC,TBM_ADD)
или
Код:

Font *fnt = eng->LoadFont("Times New Roman",14,FF_BOLD,FM_TEXCASH)
а черех описатели (Descriptors)

Код:

Texture * tex = eng->LoadTexture(TextureDesc("somefile.jpg").blend(TBM_ADD));
или
Код:

Font *fnt = eng->LoadFont(FontDesc("Times New Roman").bold(1));
минусы техники:
* обычно - больше букаф
* дополнительный класс на объект

плюсы техники:
* в сочетании с патерном мост облегчает несколько сопровождение кода при добавлении нового параметра (не нужно менять список параметров конструктора(ов) в IObject.h, CObject.h и CObject.cpp)
* можно хранить дескриптор в объекте и пользоваться фишками типа:
Код:

Font *newfont = eng->LoadFont(oldfont->GetDescriptor().bold(0));
- не знаю что за шрифт oldfont, но хаачу такой же - только нежирным чтобы был.
* можно пользоваться чем-то вроде именованных параметров, при грамотном определении умолчаний можно существенно сократить количество вводимых параметров.
* можно использовать "специальные" конструкторы. например для текстуры size(int) будет задавать одновременно и ширину и высоту (и глубину, если текса трехмерная)
* инвариант параметров. например ширина окна не может быть больше ширины дисплея, если только окно не фейковое. Правда его прийдется в конструкторе класса один фиг проверять снова, так как члены данных придется делать открытыми, чтобы конструкторы объектов имели к ним доступ. ненадежно.

Samodelkin 27.06.2010 16:21

Ответ: Описатели (Descriptors)
 
А можно попробовать объединить Описатель и класс IObject. Если к CObject применить умные указатели (которые считают количество ссылок на объект), то CObject достаточно создать один раз а IObject будет и как Описатель и как Указатель - то есть можно работать с CObject через разные Описатели. Если у Object много общих ресурсов но по разному параметризированных то это сильно сократит расходы памяти. К тому же Object будет всегда гарантировано удаляться если даже заранее не известна последовательность вызовов delete из разных потоков.

Цитата:

* инвариант параметров. например ширина окна не может быть больше ширины дисплея, если только окно не фейковое. Правда его прийдется в конструкторе класса один фиг проверять снова, так как члены данных придется делать открытыми, чтобы конструкторы объектов имели к ним доступ. ненадежно.
В том случае что я описал в функцию создания объекта окна можно передать Указатель-Описатель объекта дисплея (хотя скорей всего данные дисплея хранятся в объекте конфиге или в чем то подобном) и тогда Описатель окна обращатеся к параметрам Описателя дисплея и корректно их читает.

jimon 27.06.2010 22:36

Ответ: Описатели (Descriptors)
 
Samodelkin
Цитата:

А можно попробовать объединить Описатель и класс IObject. Если к CObject применить умные указатели (которые считают количество ссылок на объект), то CObject достаточно создать один раз а IObject будет и как Описатель и как Указатель - то есть можно работать с CObject через разные Описатели. Если у Object много общих ресурсов но по разному параметризированных то это сильно сократит расходы памяти.
это конечно хорошо, но в грамотно построенном приложении время создания и удаления объектов намного меньше времени просчёта основной логики, потому вводить чрезмерное ооп ради того чтобы в стеке не выделилось 10 кб раз в 10 секунд - оптимизации которые себя не оправдывают

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

Цитата:

К тому же Object будет всегда гарантировано удаляться если даже заранее не известна последовательность вызовов delete из разных потоков.
это хорошо, пока что-то не отвалится :)

Samodelkin 02.07.2010 17:19

Ответ: Описатели (Descriptors)
 
Вот вобщем попробовал совместить умный указатель с описателем. Конечно тут еще много чего не реализовано, но я буду продолжать.

Цитата:

это конечно хорошо, но в грамотно построенном приложении время создания и удаления объектов намного меньше времени просчёта основной логики, потому вводить чрезмерное ооп ради того чтобы в стеке не выделилось 10 кб раз в 10 секунд - оптимизации которые себя не оправдывают
А может там целая текстура в 50мб как ресурс. Вобщем то такую вещь можно и в менеджерах ресурсов исползовать.

Цитата:

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

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

DescTest.cpp
Код:


#include "DescTest.h"

void Func() {

        /*
        ======================================================================================
        Создадим указатель-описатель и сам объект.
        Вообще созданием объекта может заниматься другая функция
        или его можно получать из другой библиотеки.
        При присваивании указателю-описателю объекта счетчик указателей увеличивается на один.
        ======================================================================================
        */
        SmartPointerT<MyDesc, MyObject> sp(new MyObject());

        /*
        =================================================
        Настраиваем параметры для указателя-описателя sp.
        =================================================
        */
        sp.desc.param1 = 'a';
        sp.desc.param2 = 10;
        sp.desc.param3 = 5.0f;
        sp.desc.PrintStat(); // Выводим параметры на экран

        /*
        ==============================================================================
        Затем создадим второй указатель-описатель sp2 и скопируем параметры с sp один.
        Также можно копировать параметры и с описателей другого типа.
        Счетчик ссылок увелитися еще на один.
        ==============================================================================
        */
        SmartPointerT<MyDesc, MyObject> sp2(sp);
        sp.desc.param3 = 6.0f; // Изменим только третий параметр.
        sp.desc.PrintStat(); // Выведем на экран.

        /*
        ========================================================
        Вызовы функций объекта через разные указатели-описатели.
        Тут можно активно использовать КЭШИРОВАНИЕ ДАННЫХ -
        например один раз посчитал нахождение пути для sp и sp2
        может пользоваться готовым результатом.
        ========================================================
        */
        sp.SetParam(); // Применяем к объекту параметры дескриптора sp и работаем с объектом.
        sp.p.FuncOne();
        sp.p.FuncTwo();
        sp.SetParam(); // Применяем параметры sp2 и работаем (также можно попробовать сделать автоматическое применение параметров при вызове методов с текущего указателя).
        sp2.p.FuncThree();

        /*
        ============================================
        Перед выходом из функции sp и sp2 удаляются,
        следовательно вызываются их деструкторы,
        следовательно удаляется объект MyObject.
        ============================================
        */
}

int main() {

        Func();

        // Остановим консоль.
        char a;
        std::cin >> a;       

        return 0;
}

DescTest.hpp
Код:



#include <stdio.h>
#include <iostream>


/************************************************

 Base

************************************************/

class MyDesc;

class Base {
public:
        unsigned int        count;

                                        Base() : count(0) {
                                                std::cout << "Base::Base" << std::endl;
                                        }
        virtual                        ~Base() {
                                                std::cout << "Base::~Base" << std::endl;
                                        }
};


/*************************************************

 MyObject

*************************************************/

class MyObject : public Base {
public:
        virtual        void        FuncOne() {}
        virtual void        FuncTwo() {}
        virtual void        FuncThree() {}

        void                        SetParam(MyDesc& desc) {
                                                // Применяем параметры
                                        }
                                       
                                        MyObject() {
                                                std::cout << "MyObject::MyObject" << std::endl;
                                        }
        virtual                        ~MyObject() {
                                                std::cout << "MyObject::~MyObject" << std::endl;
                                        }
};


/*****************************************

 DescBase - MyDesc

*****************************************/

class DescBase {
public:
        virtual void        PrintStat() = 0;

                                        DescBase() {}
        virtual                        ~DescBase() {}
};

class MyDesc : public DescBase {
public:
        char                        param1;
        int                                param2;
        float                        param3;

        virtual void        PrintStat() {
                                                std::cout << "PrintStat: " << param1 << ", " << param2 << ", "<< param3 << std::endl;
                                        }

        explicit                MyDesc() {}
        explicit                MyDesc(MyDesc& desc) {
                                                param1 = desc.param1;
                                                param2 = desc.param2;
                                                param3 = desc.param3;
                                        }
        virtual                        ~MyDesc() {}
};


/*****************************************

 SmartPointer (template)

*****************************************/

template<typename D, typename P>
class SmartPointerT {
private:
        void                operator =(SmartPointerT<D, P> sp) {}
        void*                operator new(size_t bytes) {}
        void                operator delete(void* address) {}
        void                operator delete(void* address, size_t bytes) {}

public:
        P&                        p;
        D                        desc;

        void                SetParam() {
                                        p.SetParam(desc);
                                }

        explicit        SmartPointerT(P& object) : desc(), p(object) {
                                        p.count++;
                                        std::cout << "SmartPointerT::SmartPointerT\np.count = " << p.count << std::endl;
                                }
        explicit        SmartPointerT(P* object) : desc(), p(*object) {
                                        p.count++;
                                        std::cout << "SmartPointerT::SmartPointerT\np.count = " << p.count << std::endl;
                                }
        explicit        SmartPointerT(SmartPointerT<D, P>& sp) : p(sp.p), desc(sp.desc) {
                                        p.count++;
                                        std::cout << "SmartPointerT::SmartPointerT\np.count = " << p.count << std::endl;
                                }
        virtual                ~SmartPointerT() {
                                        p.count--;
                                        std::cout << "SmartPointerT::~SmartPointerT\np.count = " << p.count << std::endl;
                                        if(p.count == 0)
                                                delete &p;
                                }
};


HolyDel 02.07.2010 20:36

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

вобщем допустим у нас есть некий описатель шрифта для гуй
Цитата:

FontDesc gui_fond_dsc("Impact");
gui_fond_dsc.size = 16;
gui_fond_dsc.bold = true;
и шрифт там для игры самой
Цитата:

FontDesc game_font_dsc("Verdana");
game_font_dsc.size=12;
так вот, в игре должны быть ДВА разных шрифта обязательно. потому, что шрифт это не совсем не описатель это самостоятельная сущность. Она будет долго конструироваться, так как нужно не только загрузить сам шрифт (wglUseOutline, FT2_LoadFont, и LoadTexture) - чтобы получить сам растр(векторные данные) шрифта довольно долго будут выполняться. А кроме этого нужно еще составить кэш-текстуру для букв из юникода (если все они не влезут в одну текстуру), можно кешировать часто выводимые фразы, вобщем можно много чего сделать в конструкторе.

то, что ты предлагаешь, кстати, напоминает паттерн Приспособленец (Flyweight)
http://www.citforum.ru/SE/project/pattern/#3.1.8


Часовой пояс GMT +4, время: 13:40.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Перевод: zCarot