2008-12-02 3 views
11

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

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

ответ

13

shared_ptr <>is часть языка, начиная с выпуска TR1. (TR1)

4

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

+2

... что делает невозможным скрытие реализации интерфейсов, поскольку все они должны быть шаблонами. Не очень хорошая идея для тех, кто пытается продать проприетарное программное обеспечение. – Bklyn 2009-01-07 20:14:22

+0

@Bklyn: Я бы не осмелился использовать стороннюю C++-библиотеку, не имея, по крайней мере, ленточного источника. C++ ABI слишком хрупок. – Joshua 2010-03-22 00:16:59

6

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

3

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

18

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

3

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

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

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

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

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

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

6

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

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

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

Еще одна проблема, с которой вы можете столкнуться, заключается в том, что разные компиляторы C++ могут кастовать одни и те же символы по-разному, что означает, что вам потенциально необходимо предоставить отдельную библиотеку для каждого компилятора, который вы хотите поддерживать, даже если они используют ту же версию Boost. Ознакомьтесь с книгой «Imperfect C++» для обсуждения этого вопроса.

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

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

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

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

1

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

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

1

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

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

Смежные вопросы