Экспорт p-impl из dll
От: Chorkov Россия  
Дата: 24.07.23 10:35
Оценка:
Коли уж обсуждаю борьбу с предупреждениями...

Как побороть:
class __declspec(dllexport) Foo
{
private:
   struct Impl;
   std::shared_ptr<Impl> p_impl; // warning: C4251: 'Foo::p_impl': class 'std::shared_ptr<Foo::IImpl>' needs to have dll-interface to be used by clients of class 'Foo'

public:
// Все конструкторы/деструкторы заданы явно либо запрещены:
   Foo();
   Foo(const Foo&);
   ~Foo();
   Foo& operator=(const Foo&) = delete;

// Доступ к структуре объекта (на стороне dllimport) ненужен, 
// На стороне пользователя может оказаться другой размер класса shared_ptr?
  
// ... что-то для работы с классом. 
   int do_work(int);
};


И что можно сделать для избежания предупреждения?
Перейти на голый указатель?
Re: Экспорт p-impl из dll
От: kov_serg Россия  
Дата: 24.07.23 11:20
Оценка: 10 (1) +3
Здравствуйте, Chorkov, Вы писали:

C>И что можно сделать для избежания предупреждения?

C>Перейти на голый указатель?
Интерфейсы передавай.
struct Foo {
  virtual int queryinterface(void *uid,void **result)=0;
  virtual int addref()=0;
  virtual int release()=0;
  // ...
  virtual int do_work(int)=0;
};

int API_EXPORT create_Foo(Foo **result,void *args);
Re[2]: Экспорт p-impl из dll
От: Chorkov Россия  
Дата: 24.07.23 12:29
Оценка:
Здравствуйте, kov_serg, Вы писали:
_>Интерфейсы передавай.

А нельзя ли сохранить value семантику?
У меня, в том числе, операторы (+, -, >, <..) определены + унификация с другими value-типами, для использования в шаблонных функциях.
Через интерфейсы будет менее удобно.

Приходит в голову: экспортировать Foo::Impl как интерфейс, а Foo полностью inline.

Чем это лучше, чем
class __declspec(dllexport) Foo
{
    Impl*p_impl; 
...

и ручной подсчет ссылок в конструкторах?
Re: Экспорт p-impl из dll
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 24.07.23 14:43
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>И что можно сделать для избежания предупреждения?

Какие цели преследуешь делая так? Для чего это делаешь?
Sic luceat lux!
Re[2]: Экспорт p-impl из dll
От: Chorkov Россия  
Дата: 24.07.23 15:56
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Какие цели преследуешь делая так? Для чего это делаешь?


Я отдаю на сторону: (1) несколько библиотек с закрытым кодом, и (2) несколько библиотек "в исходниках", которые пользователь может (пере)собрать или встроить в свой проект прямо исходниками.
Все это выделяется из существующей кодовой базы, где все было единым проектом.
Библиотеки (2) используют библиотеки из (1) и (2).

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

Не везде p-impl на основе основан на shared_ptr, чаще unique_ptr. Но с ним, тоже самое предупреждение.

В качестве аргументов методов класса фигурируют либо числа, либо классы векторов и матриц (из библиотек (1)), либо std::valarray<double>.
(Почему std::valarray<double> не дает такого предупреждения, я еще не разобрался, но это тоже, наверное, ошибка.)


Простой путь: порезать проект на части, все что экспортируется пометить как __declspec(dllexport), под линукс __attribute__((visibility("default"))). Это работает и проходит тесты.

Однако предупреждения — смущают. Что если на машине пользователя другая версия CRT?
Т.е. это явная ошибка, и непонятно почему компиляторы выдают только предупреждение.

P.S.
Поскольку код из исходной кодовой базы продолжит использоваться, хочется изменения были, по возможности, минимальны. Т.е. интерфейс экспортируемых классов лучше не менять.
Отредактировано 24.07.2023 16:12 Chorkov . Предыдущая версия .
Re[3]: Экспорт p-impl из dll
От: kov_serg Россия  
Дата: 24.07.23 16:26
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>А нельзя ли сохранить value семантику?

C>У меня, в том числе, операторы (+, -, >, <..) определены + унификация с другими value-типами, для использования в шаблонных функциях.
C>Через интерфейсы будет менее удобно.
Делайте классическим способом:
int  FOO_API foo_init(void**);
void FOO_API foo_done(void**);
int  FOO_API foo_do_work(void*,int);

struct Foo {
  void *handle;
  Foo() { foo_init(&handle); }
  ~Foo() { foo_done(&handle); }
  int do_work(int x) { return foo_do_work(handle,x); }
};

// всё обёртки генерировать скриптом.

C>и ручной подсчет ссылок в конструкторах?

Причем тут подсчет ссылок, это к тому что у библиотеки может быть свой runtime и в частности свой менеджер памяти.
Re: Экспорт p-impl из dll
От: B0FEE664  
Дата: 24.07.23 17:23
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>Как побороть:

C>
C>class __declspec(dllexport) Foo
C>{
C>private:
C>   struct Impl;
C>   std::shared_ptr<Impl> p_impl; // warning: C4251: 'Foo::p_impl': class 'std::shared_ptr<Foo::IImpl>' needs to have dll-interface to be used by clients of class 'Foo'
C>


C>И что можно сделать для избежания предупреждения?

C>Перейти на голый указатель?

Теоретически можно подсунуть свой Deleter (см. struct D), а реализацию положить в dll, тогда удаление будет выполнятся там же, где и создание. Если p_impl снаружи не виден, то интерфейс не изменится.
Гарантий не даю, так как вот именно для этих целей deleter не пользовал. Что там с warning: C4251 не скажу — не знаю.
И каждый день — без права на ошибку...
Re[4]: Экспорт p-impl из dll
От: Chorkov Россия  
Дата: 24.07.23 17:35
Оценка:
Здравствуйте, kov_serg, Вы писали:


_>Делайте классическим способом:

В конце прошлого века я сам такое всем советовал.


C>>и ручной подсчет ссылок в конструкторах?

_>Причем тут подсчет ссылок, это к тому что у библиотеки может быть свой runtime и в частности свой менеджер памяти.

Различие в менеджерах памяти неважно, если право владения указателями (в т.ч. в составе объектов, таких как std::vector) не будет предаваться за пределы dll.
У меня не передается, поскольку конструкторы/деструкторы/оператор= — экспортируются, а доступа к приватным членам нет, в том числе со стороны членов класса, генерируемых компилятором (потому что их нет).
Из опасностей остается:
1) различие в выравнивании (если в классе несколько членов),
2) различение в реализации передаваемых объектов (std::vector может хранить два указателя, а может указатель и длину, или длина будет храниться в блоке под указателем,... )
3) Передаваемые объекты не должны содержать inline (или генерируемых компилятором) членов, которые вызывали бы функции C-runtime или C++-runtime, который действительно может измениться. Это было бы нарушением ODR.

Собственно п.(2) и (3) не позволяют передавать объекты стандартной библиотеки под windows. (Под linux проблемы нет, но мне нужны обе платформы.)
Re[5]: Экспорт p-impl из dll
От: kov_serg Россия  
Дата: 24.07.23 17:51
Оценка:
Здравствуйте, Chorkov, Вы писали:

_>>Делайте классическим способом:

C>В конце прошлого века я сам такое всем советовал.
Так в C++ добавили дофига всякого не нужного хлама, а вот для работы с динамическими библиотеками руки пачкать не хотят.

C>Различие в менеджерах памяти неважно, если право владения указателями (в т.ч. в составе объектов, таких как std::vector) не будет предаваться за пределы dll.

Самый оптимальный вариант с интерфейсами.

C>У меня не передается, поскольку конструкторы/деструкторы/оператор= — экспортируются, а доступа к приватным членам нет, в том числе со стороны членов класса, генерируемых компилятором (потому что их нет).

В интерфейсах вообще ни слова о приватных полях, только публичные методы.

C>Из опасностей остается:

C>1) различие в выравнивании (если в классе несколько членов),
C>2) различение в реализации передаваемых объектов (std::vector может хранить два указателя, а может указатель и длину, или длина будет храниться в блоке под указателем,... )
C>3) Передаваемые объекты не должны содержать inline (или генерируемых компилятором) членов, которые вызывали бы функции C-runtime или C++-runtime, который действительно может измениться. Это было бы нарушением ODR.
Всё это хорошо скрывается интерфейсами. В том числе и выравнивание, и исключения ныкаются через HRESULT.

C>Собственно п.(2) и (3) не позволяют передавать объекты стандартной библиотеки под windows. (Под linux проблемы нет, но мне нужны обе платформы.)

Вы можете и из под виндовс иметь общий runtime если будете стандартную билиотеку динамически линковать. Но это будет квази динамическая библиотека, она будет прибита к версии рунтайма гвоздями. Т.е. если это плагин то он должен собираться строго с той же версией стандартных dll иначе не загружаться или же просто рассыпаться.
Re: Экспорт p-impl из dll
От: Teolog  
Дата: 24.07.23 18:56
Оценка: +1
наружу точит shared_ptr — а не должен, он у всех свой, уникальный. Разного размера и состава.
Об том и намекает — если собирать все модули с одними настройками за один проход — можно игнорировать, если отдельно — надо внедрять защиту от дурака.
Re[3]: Экспорт p-impl из dll
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 24.07.23 23:21
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>Простой путь: порезать проект на части, все что экспортируется пометить как __declspec(dllexport), под линукс __attribute__((visibility("default"))). Это работает и проходит тесты.

Лучше взять Boost.dll или подобные решения. На форуме, кстати, были и статьи, и обсуждения "плагинных" вопросов.
C>Однако предупреждения — смущают. Что если на машине пользователя другая версия CRT?
С этим будут проблемы рано или поздно в виде разных ошибок. Можно их сократить НЕ работая с памятью через границы модулей. Для винды кардинальное решение всех проблем, очевидно, COM.
Sic luceat lux!
Re: Экспорт p-impl из dll
От: Sm0ke Россия ksi
Дата: 25.07.23 11:15
Оценка:
Здравствуйте, Chorkov, Вы писали:

Сделать свою версию для unique_ptr, shared_ptr, vector
Которые будут работать с памятью через указатель на функцию.
Хранить в них fn_deleter из библиотеки для смарт поинтеров, как мемберы
Хранить fn_alloc, fn_dealloc для вектора. Таким образом работа с памятью будет инкапсулирована в той dll/exe, в которой был создан объект (объявлена переменная).

Да, это странное предложение велосипедить такие стандартные штуки. Но что делать, если стандартные не годятся на границе бинарников.
Re[2]: Экспорт p-impl из dll
От: kov_serg Россия  
Дата: 25.07.23 12:18
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Да, это странное предложение велосипедить такие стандартные штуки. Но что делать, если стандартные не годятся на границе бинарников.


Если стандартные штуки для таких простых типовых задач не подходят, то стандарт c++ вызывает лёгкую улыбку
Re[3]: Экспорт p-impl из dll
От: so5team https://stiffstream.com
Дата: 25.07.23 13:09
Оценка:
Здравствуйте, kov_serg, Вы писали:

S>>Да, это странное предложение велосипедить такие стандартные штуки. Но что делать, если стандартные не годятся на границе бинарников.


_>Если стандартные штуки для таких простых типовых задач не подходят, то стандарт c++ вызывает лёгкую улыбку


А стандарт-то хоть про DLL в курсе вообще?
Re[4]: Экспорт p-impl из dll
От: kov_serg Россия  
Дата: 25.07.23 17:00
Оценка:
Здравствуйте, so5team, Вы писали:

_>>Если стандартные штуки для таких простых типовых задач не подходят, то стандарт c++ вызывает лёгкую улыбку


S>А стандарт-то хоть про DLL в курсе вообще?


Да они даже не в курсе что есть gui, конфигурационные файлы и базы данных, не говоря уже о векторной и растровой графике.
Они даже не понимают зачем сжимать бинарные библиотеки *.lib и *.so
Re[5]: Экспорт p-impl из dll
От: so5team https://stiffstream.com
Дата: 25.07.23 17:06
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>>>Если стандартные штуки для таких простых типовых задач не подходят, то стандарт c++ вызывает лёгкую улыбку


S>>А стандарт-то хоть про DLL в курсе вообще?


_>Да они даже не в курсе что есть gui, конфигурационные файлы и базы данных, не говоря уже о векторной и растровой графике.


И это хорошо. Должно быть больше библиотек, хороших и разных.

_>Они даже не понимают зачем сжимать бинарные библиотеки *.lib и *.so


Опять же, стандарт-то хоть в курсе про наличие .lib/.a и .dll/.so?

Полагаю, что нет. Все это за рамками стандарта. Так с чего улыбка, если стандарт к этому вообще никаким боком?
Re[6]: Экспорт p-impl из dll
От: kov_serg Россия  
Дата: 25.07.23 17:36
Оценка:
Здравствуйте, so5team, Вы писали:

S>Полагаю, что нет. Все это за рамками стандарта. Так с чего улыбка, если стандарт к этому вообще никаким боком?

Всё что полезно и регулярно нужно, в стандарт не вошло, в очередной раз.
Re[7]: Экспорт p-impl из dll
От: so5team https://stiffstream.com
Дата: 26.07.23 04:10
Оценка: +1
Здравствуйте, kov_serg, Вы писали:

S>>Полагаю, что нет. Все это за рамками стандарта. Так с чего улыбка, если стандарт к этому вообще никаким боком?

_>Всё что полезно и регулярно нужно, в стандарт не вошло, в очередной раз.

"Всё что полезно и регулярно нужно" в стандарт в принципе войти не может, уж больно много этого разного полезного и нужного.

Меня, например, очень бы обрадовало включение в стандарт какого-то дешевого механизма исключений. Чтобы, наконец, уйти от ситуации, когда в половине проектов исключения под полным запретом.

А вот появление в стандарте условного GUI, напротив, огорчило бы.
Re[8]: Экспорт p-impl из dll
От: andyp  
Дата: 26.07.23 12:42
Оценка:
Здравствуйте, so5team, Вы писали:

S>Меня, например, очень бы обрадовало включение в стандарт какого-то дешевого механизма исключений.


Вот два пива этому столику!

Помню, как то смотрел видео Саттера на CppCon про исключения — уже тогда подумал, что это чуть ли не самое дельное из того, что предлагал Микрософт в последнее время.
Re[9]: Экспорт p-impl из dll
От: so5team https://stiffstream.com
Дата: 26.07.23 12:47
Оценка:
Здравствуйте, andyp, Вы писали:

A>Помню, как то смотрел видео Саттера на CppCon про исключения — уже тогда подумал, что это чуть ли не самое дельное из того, что предлагал Микрософт в последнее время.


Только вот ждем-с и ждем-с...

Могу ошибаться, но кажется Антон Полухин в комментариях к очередной статье на Хабре про нововведения в C++ обмолвился, что это предложение подвисло и перспективы у него были так себе. Подробностей, к сожалению, уже не вспомню
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.