Suslik
Про этот вариант я упоминал в посте #16, в этом случае ты решаешь проблему путем сохранения в конкретной реализации текстуры ссылки на конкретную реализацию девайса. Т.е. твой код вообще можно свести к минимуму:
class ITexture { virtual void Bind() = 0; } class IDevice { ITexture *CreateTexture(); } class DXTexture : public Texture { DXTexture(DXDevice *owner) { this.owner = owner; } void Bind() { // we already have all the API-specific details here } DXDevice *owner; }
Т.е. сразу вызываем бинд текстуры, девайс не указываем - все равно он внутри сохранен.
Проблема в том, что при этом возрастает связанность системы (сохранение указателя на одну реализацию внутри другой реализации). Считается, что это какбе нехорошо.
winter
> Проблема в том, что при этом возрастает связанность системы (сохранение указателя на одну реализацию внутри другой реализации). Считается, что это [i]какбе[/i] нехорошо.
обалденная история, бро. часто ты собрался заменять одну из сущностей: текстура-девайс? если они в принципе реализовывались как составляющие одной системы(об этом говорит хотя бы одинаковый префикс/неймспейс), то с какой стати они вдруг должны быть несвязаны и отдельно заменяемы? они как бы идеологически жить друг без друга не могут.
> Т.е. твой код вообще можно свести к минимуму:
я у себя в домашних мультирендер-проэктах так и делаю. одна связка дейвайсы-шрифты-рендертаргеты == одна dll, поставляются комплексом и одну текстуру взять из одной длл(GL), а девайс - из другой(софтвар) взять нельзя как теоретически, так и практически.
тайпкасты кроме самых крайних случаев(описанные в этом треде случаи даже не близки к крайним) не использую.
crsib
>> Соответственно тайпкаст более чем оправдан
Если ты используешь тайпкаст, то:
- либо ты программируешь на жаве/шарпе и активно используешь существующий фреймворк;
- либо ты - плохой программист.
Прости, но это так. Использование тайпкастов приводит к созданию неконтролируемого кода и должно караться немедленным увольнением с наихудшей рекомендацией.
Suslik
Суслик, а почему речь идет лишь о замене сущностей?
Сохраняем мы внутри текстуры указатель на девайс - естественно, умный указатель... А внутри девайса сохраняем умный указатель на текущую активную текстуру, чтобы по пять раз не биндить... И алгоритм сборки мусора получает цикл, который нужно разруливать.
Это, разумеется, абсолютно решабельная проблема, но создание таких "закольцованных" ссылок обычно считается, ммм, плохим тоном.
winter
> Прости, но это так.
Прости, но это не так. апкаст не допустим тогда, когда мы не можем гарантировать тип объекта на этапе компиляции или в рантайме. В данном конкретном случае - можем. При большем желании даже в рантайме и очень быстро. Правда это потребует дополнительного костыля к С++, но в С++ много что требует костылей.
Подход Suslik хорош, но как ты заметил
>Проблема в том, что при этом возрастает связанность системы (сохранение указателя на одну реализацию внутри другой реализации). Считается, что это какбе нехорошо
Suslik
Хотя решение, не спорю, абсолютно валидное. У меня тоже указатели на реализацию девайса до недавнего времени сохранялись в реализациях текстур/шейдеров, пока я не заменил всю эту кухню более медленным двойным диспатчингом.
Метод Suslik это и есть двойная диспетчеризация
crsib
Ну окей, допустим, ты не согласен с моей позицией по поводу апкастов (а я категорически не согласен с твоей). Но ты хотя бы не будешь спорить с простым фактом, что любой апкаст - это борьба с собственной, своими руками созданной абстракцией? Т.е. проблема налицо? И Торвальдс не сотрясает попусту воздух?
crsib
Нет, двойная диспетчеризация - это то, что я написал в нулевом посте. Она не увеличивает уже существующую связанность системы. А метод Суслика (и мой метод тоже, до какого-то момента) - это сохранение указателя на одну реализацию внутри другой реализации, увеличивающее связанность системы еще больше и потенциально ведущее к возникновению "закольцованных" ссылок.
Да, согласен. Но создание абстракций решает (должно решать) больше проблем, чем в итоге создает. Метод Торвальдса и WinAPI гораздо менее контролируемый и гораздо менее расширяемый. А вопрос, как разрешать кто криветко является экземпляром какого класса это тема отдельной дискуссии и, на мой взгляд, общие решения не всегда подходят, особенно для сильно связанных систем, в которых мы можем гарантировать, какая реализация будет использована
winter
> Суслик, а почему речь идет лишь о замене сущностей?
>
> Сохраняем мы внутри текстуры указатель на девайс - естественно, умный
> указатель... А внутри девайса сохраняем умный указатель на текущую активную
> текстуру, чтобы по пять раз не биндить... И алгоритм сборки мусора получает
> цикл, который нужно разруливать.
>
> Это, разумеется, абсолютно решабельная проблема, но создание таких
> "закольцованных" ссылок обычно считается, ммм, плохим тоном.
ёлки-палки, ну смотри:
текстура формально неотделима от девайса. ты не можешь текстуру одного девайса приаттачить к другому. это невозможно логически и не должно быть возможно практически, даже попытаться. таким образом, у тебя не может текстура существовать отдельно от девайса. это ни плохо, ни хорошо, просто в данной задаче это вот так есть. ну а девайсу, как ты заметил, где-то нужно хранить указатель на свои текстуры, например, на текущую активную. dummy-смартпойнтер не вытянет циклическую ссылку, какой ужас. может быть, это проблема dummy-смартпойнтера, а не орхетектурного подхода?
winter
> Нет, двойная диспетчеризация - это то, что я написал в нулевом посте.
В данном случае и это тоже. И твой метод тоже увеличивает связность системы и усложняет ее расширение. Есть другие подходы к реализации двойной диспетчеризации.
> увеличивающее связанность системы еще больше и потенциально ведущее к возникновению "закольцованных" ссылок.
В этом случае твой подход не только не решает проблемы, но и потенциально делает код опасным. В данном конкретном случае (мы ведь рассматриваем именно его) мы не можем делать бинд текстуры, созданной на одном девайсе на другой девайс. Соответственно, проверка "а та ли текстура" должна выполняться девайсом в любом случае. Если проверка выполнена успешно, то мы точно гарантируем, что интерфейс имеет фиксированную реализацию.
Еще раз. Обрати внимание, что я всегда говорю именно в контексте приведенного тобой примера. В общем случае, описываемый мной подход не применим и я с этим ни коим образом не спорю
а вообще если тебе не нравятся ссылки, тайпкасты и прочая муть, будь мужиком, делай как все покемоны, у них, что характерно, это считается нормально:
class Device { virtual int CreateTexture() = 0; virtual void BindTexture( int texId) = 0; };
ну или даже так:
class Texture { Texture(std::string name) { this->name = name; } std::string name; }; class Device { virtual Texture CreateTexture( std::string name) = 0; virtual void BindTexture( Texture tex) = 0; }; class DXDevice : public Device { virtual Texture CreateTexture( std::string name) { Texture tex( name); textures[tex] = new DXTexImpl( ); return tex; } virtual void BindTexture( Texture tex) { textures[tex].SomeNativeMethod( ); } std::map<Texture, DXTexImpl *> textures; }
Suslik
>> текстура формально неотделима от девайса. ты не можешь текстуру одного девайса приаттачить к другому. это невозможно логически и не должно быть возможно практически, даже
>> попытаться.
А вот и фигню ты спорол только что, бро! Слыхал про функцию из состава OpenGL API, wglShareLists()? Она расшаривает таблицы дескрипторов одного девайса на другой девайс (в огле они называются контекстами).
Пример: ОГЛ создает по отдельному контексту для каждого треда (!) в составе процесса. И если ты хочешь юзать текстуру в разных тредах многопоточного приложения, изволь расшарить ее. У меня как раз недавно была такая проблема, когда я делал двухпоточный дебаггер шейдеров.
Для ДХ сказанное тобой, однако, верно. Проблема в том, что решение с дабл-диспатчингом учитывает даже такие детали, о которых ты не подозреваешь.
Suslik
>> а вообще если тебе не нравятся ссылки, тайпкасты и прочая муть, будь мужиком, делай как все покемоны, у них, что характерно, это считается нормально
Суслик... НУ ЭТО ЖЕ ДЕСКРИПТОРЫ. Я про них уже третью странцу талдычу, черт... Сишный WinAPI-style подход, когда все методы - у девайса, а юзеру выдается только дескриптор текстуры без методов...
Тема в архиве.