Как стать автором
Обновить

Как обеспечить надлежащее пересечение границ динамической библиотеки, используя пользовательские средства удаления смарт-указателей

Время на прочтение4 мин
Количество просмотров9.7K
Всего голосов 14: ↑11 и ↓3+8
Комментарии11

Комментарии 11

А что будет если default_delete<MyClass>::operator() заинлайнится компилятором, и соответственно его тело вызовется не из того модуля где объект создан, а из вызывающего?
Что значит если? Вообще-то он будет заинлайнен компилятором (в смысле правил линковки), поскольку определение метода приведено в определении класса. С другой стороны, это элементарно решается разделением объявления и реализации и переносом реализации в файл исходных кодов.
Ну кто его знает. Может __declspec(dllimport/dllexport) для класса предотвращает встраивание методов.

Во-вторых, по никакого обязательного будет нет.
Компилятор может встроить метод, а может вызвать его. Во втором случае символ метода будет прилинкован согласно типу связывания (в MSVC он задается атрибутом dllimport), т.е. будет скорее всего использован правильный метод из другой ДЛЛ.

А задавал я вопрос потому что не уверен что приведенное решение гарантирует что-либо.
(Ну а насчет того работает ли оно вообще — поверил автору)
Я имел в виду «встривание» в смысле действий правил линковки.

Сейчас уточнил, действительно, это просто UB:

7.1.2 Function specifiers [dcl.fct.spec]

2 A function declaration (8.3.5, 9.3, 11.3) with an inline specifier declares an inline function. [...] An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.

3 A function defined within a class definition is an inline function. [...]

4 An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly
the same definition in every case (3.2)
. [...]

4) не выполняется, потому что delete определен в разных библиотеках по разному.
А зачем функцию std::unique_ptr< MyClass > create() const оставлять в хедере? В данном случае, я не вижу проблемы того, что unique_ptr будет создан в библиотеке. Сам по себе unique_ptr память не выделяет.

Более того, мне кажется, что и определять свой собственный default_delete< MyClass > не обязательно. Если создавать в объект unique_ptr внутри библиотеки, не указывая deleter, будет создан объект класса по умолчанию и отдан unique_ptr-у по значению. Когда мы будем отдавать unique_ptr, то deleter будет перемещен в новый unique_ptr. То есть, клиент получит deleter из библиотеки.

Суммируя, библиотека должна просто создавать отдавать unique_ptr или shared_ptr и все должно работать само по себе. Или я что-то упускаю?

edit: вдогонку, ссылка, подтверждающая мою мысль stackoverflow.com/a/5835036/661451
Прошу прощения, моя оплошность. Реализация всех функций должна быть в отдельных файлах
Прошу прощения, нечаянно создал отдельный комментарий вместо ответа. habrahabr.ru/post/182970/#comment_6415596
Ок, это отвечает на первый вопрос. Но это мелочи.
Меня больше интересует, насколько верно мое рассуждение, что современные умные указатели настолько умные, что ничего делать не надо, а все есть?
У вас файл DllSwitch.h не имеет ничего общего с С++. Таких конструкций или ключевых слов, как «declspec» и "#pragma once", в языке С++ не существует.
1. Я думаю тут ожидалась ссылка на главу стандарта c++, но в нём таких слов нет насколько я помню.

2. Если отвлечься от стандарта и вернуться к реальности, то #pragma once это нормально — сейчас сложно найти компилятор который не поддерживает её. Но __declspec это как минимум windows-specific (вообще-то microsoft specific).

Думаю чтобы избежать подобных придирок надо было указать что речь только про MSVC либо чуть усложнить DllSwitch.h добавив поддержку для gcc хотя бы (ссылка для изучения: gcc.gnu.org/wiki/Visibility )
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории