Войти
ФлеймФорумПрограммирование

Деокмпозиция сложных вызовов API с указателями

Страницы: 1 2 3 Следующая »
#0
(Правка: 2 мар. 2021, 5:29) 15:50, 1 мар. 2021

Допустим, есть некое сторонее API вот с такой сигнатурой:

  struct Params {
    A* a;
    B* b;
    C* c;
    D* d;
    E* e;
    F* f;
    G* g;
  };
  Result callMe(Params params);

Где A-G - структурки с 1-20 полями, некоторые из которых тоже указатели. в таком духе:

  struct A {
    int x;
    int y;
    int* zs;
    int zCount;
  };

После отработки метода callMe, структуры нам более не нужны.

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

Какие варианты я вижу:

1. привыкать к простынкам

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

3. выделить под вызов апишечки отдельный временный класс (что-то вроде паттерна builder), аллоцируя структуры и вложенные массивы в виде полей класса, которые очистятся автоматом

4. забубенить колхозный менеджер ссылок!

+ Показать

В общем, прошу продиагностировать стадию моей наркомании и выписать рецепт.

#1
16:09, 1 мар. 2021

kkolyan
Мудрый указатель, не?

#2
16:15, 1 мар. 2021

nes
> Мудрый указатель, не?
помог бы, если бы не вложенные указатели в структурах.

#3
16:26, 1 мар. 2021

kkolyan
Чо-нибудь такое не покатит?

+ Показать
#4
(Правка: 16:36) 16:29, 1 мар. 2021

nes
не совсем понимаю как это использовать с пользой. чем это лучше варианта номер 4?

#5
16:32, 1 мар. 2021

kkolyan
Ой, это считай оно и есть, пирдон, недочитавший )

#6
21:10, 1 мар. 2021

nes
почитал повнимательнее - это ближе к третьему решению, судя по всему.

#7
23:31, 1 мар. 2021

kkolyan
> это ближе к третьему решению
Да, это оно и есть. Тоже плюсую к третьему решению.
К тому же, в мире c++ указатели обычно хранятся в каких-нибудь unique_ptr - тогда ручками ничего удалять не надо - всё в лучших традициях RAII. Или вообще, если допустимо, можно ссылаться на переменную со стека. Вариантов враппера - море.

#8
(Правка: 0:25) 0:23, 2 мар. 2021

SST | Деокмпозиция сложных вызовов API с указателями

#9
(Правка: 0:34) 0:33, 2 мар. 2021

gudleifr
вообще этот тред вдохновлен Vulkan-ом, а не WinAPI:)

#10
0:46, 2 мар. 2021

pahaa
> К тому же, в мире c++ указатели обычно хранятся в каких-нибудь unique_ptr - тогда ручками ничего удалять не надо - всё в лучших традициях RAII.
в своем коде - да, но сторонняя апишечка вот требует голых указателей, да еще и со вложенностью. я так понимаю, такие интеграции сплошь и рядом и нужно уметь с таким сосуществовать.

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

#11
(Правка: 1:04) 1:04, 2 мар. 2021

kkolyan
> вообще этот тред вдохновлен Vulkan-ом, а не WinAPI:)
Это без разницы. Суть построения "оболочек для API-вызовов" от этого не меняется.

#12
4:07, 2 мар. 2021

Не вижу проблемы.
Структуры A-G разместить тут же в стеке как локальные переменные, раз они нам после вызова callMe больше не нужны. Удалятся сами без возни с new/delete.
Если охота их инициализацию вынести в отдельные функции/методы сделать вот так:

void initA( A *a, .... );
Или ссылкой.
Старый дедовский проверенный способ.

#13
4:38, 2 мар. 2021

kkolyan
> сторонняя апишечка вот требует голых указателей
я как раз вот об этом:
=A=L=X=
> разместить тут же в стеке как локальные переменные, раз они нам после вызова
> callMe больше не нужны
при чём разместить их можно даже не просто на стеке, а вообще в качестве полей класса-обёртки
например вот так всё аллоцируется на стеке, но полностью инкапсулировано:

struct WrapperA {
  A data;
  int sz = 0;
  WrapperA() { data.sz = &sz; }
};
struct ParamsWrapper {
  Params data;
  WrapperA a;
  ParamsWrapper() { data.a = &a.data; }
};
ParamsWrapper params;
Result result = callMe(params.data);
если же по какой-то причине на стеке нельзя, то заменяем int sz на unique_ptr<int> sz
#14
(Правка: 5:28) 5:06, 2 мар. 2021

=A=L=X=

> Структуры A-G разместить тут же в стеке как локальные переменные, раз они нам после вызова callMe больше не нужны
это вариант 1 - простынка. большая, плохонавигируемая, в которой смешано много разного.

> void initA( A *a, .... );
это, видимо, среднее между вариантом 2 и 3.
проблема в том, что тогда вложенные указатели оказываются без присмотра. после выхода из "initA" они окажутся либо невалидны, либо увековечены. собственно мой вариант 4 - это и есть "initA", но с решением проблемы вложенных ссылок.


pahaa

> например вот так всё аллоцируется на стеке, но полностью инкапсулировано:
ага, это прям вариант 3. как раз переписал все на него, эксперимента ради. и выглядит прямо 1 в 1 как в твоем примере.

> если же по какой-то причине на стеке нельзя
можно конечно. главная цель - максимально разгрузить главный метод, вынеся специфичный для каждой компоненты код в отдельные методы/классы.

ну собственно твоя позиция мне теперь понятна на 146%. единственно, интересно услышать хотя-бы вскользь что-нибудь про вариант 4.

Страницы: 1 2 3 Следующая »
ФлеймФорумПрограммирование