Использование boost::shared_ptr в общедоступном интерфейсе библиотеки

StackOverflow https://stackoverflow.com/questions/335330

  •  22-07-2019
  •  | 
  •  

Вопрос

У нас есть библиотека C ++, которую мы предоставляем нескольким разным клиентам.Недавно мы перешли от использования необработанных указателей в общедоступном интерфейсе к использованию boost::sharedptr вместо этого.Как вы можете догадаться, это дало огромное преимущество в том смысле, что теперь клиентам больше не нужно беспокоиться о том, кому, что и когда нужно удалить.Когда мы переключились, я верил, что это правильно, но меня беспокоило, что нам пришлось включить что-то из сторонней библиотеки в наш общедоступный интерфейс - обычно вы избегаете подобных вещей, если можете.Я объяснил это тем, что boost теперь практически стал частью языка C ++, и наш вариант использования требует, чтобы и клиентский код, и библиотека содержали указатели на объекты.Однако недавно один из наших клиентов спросил нас, можем ли мы переключиться на использование нейтрального класса smart pointer в интерфейсе, потому что наша библиотека, по сути, вынуждает их использовать определенную версию boost - момент, который я, безусловно, понимаю и ценю.Так что теперь я задаюсь вопросом, каким мог бы быть наилучший план действий.Я немного подумал об этом и задумался о создании простого класса интеллектуальных указателей, который просто содержал бы интеллектуальный указатель real boost.Но тогда клиенты, вероятно, сразу же вставили бы один из них в свой вариант boost::shared_ptr, и тогда у нас было бы три общих указателя - что может быть проблемой, а может и нет.В любом случае, я хотел бы услышать несколько мнений сообщества о наилучшем способе решения этой проблемы.

Редактировать:Первоначально я сказал о передаче права собственности, но я должен был указать, что код по обе стороны границы API должен содержать указатель на объект.

Это было полезно?

Решение

shared_ptr ( общий файл )<> является часть языка, начиная с выпуска TR1.Видишь: (TR1)

Другие советы

Одним из возможных решений является поддержка boost :: shared_ptr с вашим проектом. Поскольку все это состоит из заголовков, это избавит ваших клиентов от необходимости устанавливать библиотеки boost вручную. Вы можете использовать bcp , чтобы получить все файлы, необходимые для определенная библиотека повышения, включая сами библиотеки. Я сделал это, когда работал тогда в компании и нуждался в boost::shared_ptr, и это действительно сработало.

Если семантика действительно передача права собственности , почему бы не использовать auto_ptr, поскольку это стандартный C ++? Внутренне вы все равно можете создать свой shared_ptr из auto_ptr, а затем иметь общее владение, если вам это нужно.

Прежде всего, если вы распространяете свою библиотеку как исходный код, а не как скомпилированную библиотеку, вы можете игнорировать этот ответ. Есть также некоторые специфичные для Windows проблемы, которые могут не относиться к другим платформам.

Лично я считаю, что вам следует избегать использования слишком большого количества фантичного c ++ в публичном интерфейсе вашей библиотеки, поскольку это может вызвать много проблем у клиента.

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

Другая проблема, с которой вы можете столкнуться, заключается в том, что разные компиляторы c ++ могут по-разному обрабатывать одни и те же символы, что означает, что вам потенциально необходимо предоставить отдельную библиотеку для каждого компилятора, который вы хотите поддерживать, даже если они используют одну и ту же версию Boost. Посмотрите книгу & Quot; Несовершенный C ++ & Quot; для обсуждения этого.

В нынешнем мире различных компиляторов и сред C ++ я считаю, что печальная истина заключается в том, что вам следует избегать использования в интерфейсе чего-либо, кроме C, и обеспечивать динамическое связывание вашей библиотеки (чтобы избежать конфликтов при связывании ваших клиентов с ссылками на вашу библиотеку, библиотека времени выполнения Windows может быть настоящей болью здесь). Вы по-прежнему можете использовать boost и столько же модного c ++ внутри вашей библиотеки, сколько пожелаете, поскольку все ваши символы будут изолированы от среды ваших клиентов в dll.

Если вы действительно хотите иметь интеллектуальные указатели и другие приятные функции C ++ в интерфейсе вашей библиотеки, создайте удобный слой, для которого вы распространяете исходный код. Это гарантирует, что он всегда компилируется в среде клиентов. Этот интерфейс затем вызывает ваши открытые функции C хитрыми способами. Я не думаю, что будет хорошей идеей использовать повышение в этом слое, так как это заставит ваших клиентов принять его, даже если они этого не хотят, однако его легко заменить или найти другое решение, так как этот слой распространяется как источник код.

Еще одна приятная особенность заключается в том, что обычно проще вызывать функции C в dll, чем функции c ++ со странным искажением имен, если вы хотите представить свою библиотеку другим языкам, кроме C / C ++.

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

Это C ++. Вы знаете, вы можете шаблонизировать интерфейсный класс поверх реализации общего указателя.

Это интересный вопрос, который у меня был в течение некоторого времени. Вы принуждаете своих пользователей к любой библиотеке, которую вы предоставляете, или позволяете им решать, что лучше в их проекте? Как всегда, вопрос в том, что вы предлагаете и чего вы требуете от пользователя.

Если вы используете сырые указатели, вы допускаете всевозможные возможности. Пользовательский код может использовать необработанный указатель, сохранять его в std :: auto_ptr, shared_ptr (будь то boost или TR1) или в своей домашней версии умного указателя. Но это также может привести к проблемам у пользователя, если он забудет освободить память, и потребуется еще немного кода на его стороне, если он просто захочет создать временный объект для вызова метода (если вы предоставите необработанные указатели, им придется хранить указатель во временную [возможно умную] переменную указателя).

Теперь, если вы используете умный указатель, вы навязываете свое решение пользователю. Если они планируют использовать собственную версию интеллектуального указателя (скажем, вы используете boost :: shared_ptr и им нужен std :: tr1 :: shared_ptr), им больше не разрешено использовать его, если они работают с вашим интерфейсом. Какой бы умный указатель вы ни выбрали (кроме специального std :: auto_ptr), вы не только навязываете решение, но и проблемы, которые у него есть.

Если у вашего пользователя есть многопоточное приложение, а ваше решение не является поточно-ориентированным, оно связано с небезопасным решением. Если, с другой стороны, интеллектуальный указатель является потокобезопасным, но влечет за собой затраты на блокировку, эти затраты переносятся на пользователей, даже если они работают в многопоточном приложении. Если вы компилируете свою библиотеку (не только lib из заголовков), то вы используете не только тип интеллектуального указателя, но и его конкретную версию, поскольку любые изменения в библиотеке интеллектуального указателя нарушат совместимость вашего кода.

Примечание: boost :: shared_ptr (boost 1.33+) - это многопоточный в большинстве ситуаций, и он использует реализацию без блокировки на многих платформах. В любом случае, это должно дать вам представление о вещах, которые вы должны рассмотреть.

Наконец, вы должны учитывать, что вы не только привязываете пользователя к использованию вашего типа интеллектуального указателя, но также и его версии. Если вы компилируете свою библиотеку для определенной версии boost, пользователь будет привязан к этой конкретной реализации o

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

введение boost :: shared_ptr заставляет вашего клиента использовать boost. для некоторых это незначительная проблема.

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

Используйте auto_ptr или придерживайтесь интерфейса C. Заставить библиотеки C ++ в ваш интерфейс всегда отвратительно, убивает любые шансы стать кроссплатформенным и вызывает кошмар обслуживания у клиентов с разными & Quot; downstream & Quot; конфигурации.

Как только C ++ 0x станет достаточно популярным для ваших клиентов, переключитесь на std::shared_ptr.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top