Использование boost :: shared_ptr в публичном интерфейсе библиотеки - PullRequest
11 голосов
/ 02 декабря 2008

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

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

Ответы [ 10 ]

18 голосов
/ 03 декабря 2008

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

13 голосов
/ 02 декабря 2008

shared_ptr <> является частью языка, начиная с выпуска TR1. См .: (TR1)

6 голосов
/ 03 декабря 2008

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

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

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

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

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

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

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

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

6 голосов
/ 02 декабря 2008

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

4 голосов
/ 02 декабря 2008

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

3 голосов
/ 03 декабря 2008

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

Если вы используете сырые указатели, вы допускаете всевозможные возможности. Пользовательский код может использовать необработанный указатель, сохранять его в 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

3 голосов
/ 03 декабря 2008

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

2 голосов
/ 02 декабря 2008

boost :: intrusive_ptr возможно?

1 голос
/ 22 июля 2010

Используйте auto_ptr или придерживайтесь интерфейса C. Заставить библиотеки C ++ в ваш интерфейс всегда отвратительно, убить любой шанс стать кроссплатформенным и вызвать кошмар обслуживания для клиентов с различными «нисходящими» конфигурациями.

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

1 голос
/ 22 июля 2010

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

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

...