Avoiding reinventing the wheel for a public api with binary compatibility in mind

View: New views
11 Messages — Rating Filter:   Alert me  

Avoiding reinventing the wheel for a public api with binary compatibility in mind

by Geoff Hilton :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I'm writing a public api for a product which will be bundled as a
precompiled dll or binary and one of my goals is binary compatibility
(if not across major versions, at least across minor). I'd like to
implement the pimpl idiom and reference counting for the handle classes
as appropriate, but I'm worried about all the typical stuff (exception
safety, memory leaks, etc) and I'd rather not reinvent the wheel.

eg.
template<typename T>
class MyClass {
public:
T foo();
private:
boost::shared_ptr<MyClassImpl<T> > impl;
};

Using boost::shared_ptr would be great, but this means clients of my
code would have to have the same version of boost installed that we use,
and I imagine this could cause conflicts in the event that they happen
to use boost (and a different version of it). I'd rather not include
more code dependencies than I absolutely have to, especially if they may
prove problematic in the future. What do I do? I know I'm not the first
in this situation. How often have others opted for this dependency as
opposed to furnishing their own alternative that would avoid additional
dependencies (at the expense of the benefit of time-tested code)?

_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: Avoiding reinventing the wheel for a public api with binary compatibility in mind

by Emil Dotchevski-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Nov 4, 2009 at 5:16 PM, Geoff Hilton
<geoff.hilton@...> wrote:

> Using boost::shared_ptr would be great, but this means clients of my code
> would have to have the same version of boost installed that we use, and I
> imagine this could cause conflicts in the event that they happen to use
> boost (and a different version of it).

In theory, yes, they must use the same version of boost. In practice,
you'll be surprised how resilient shared_ptr is to breaking binary
compatibility across boost versions.

That said, if you want to be bullet-proof, you can do pimpl the old fashion way:

struct foo;
foo * create_foo(....);
void destroy_foo( foo * );
void use_foo( foo * );

Note that users can still easily use shared_ptr:

boost::shared_ptr<foo> x(create_foo(....),destroy_foo);

Emil Dotchevski
Reverge Studios, Inc.
http://www.revergestudios.com/reblog/index.php?n=ReCode
_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: Avoiding reinventing the wheel for a public api with binary compatibility in mind

by Nigel Rantor :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Geoff Hilton wrote:

> I'm writing a public api for a product which will be bundled as a
> precompiled dll or binary and one of my goals is binary compatibility
> (if not across major versions, at least across minor). I'd like to
> implement the pimpl idiom and reference counting for the handle classes
> as appropriate, but I'm worried about all the typical stuff (exception
> safety, memory leaks, etc) and I'd rather not reinvent the wheel.
>
> eg.
> template<typename T>
> class MyClass {
> public:
> T foo();
> private:
> boost::shared_ptr<MyClassImpl<T> > impl;
> };
>
> Using boost::shared_ptr would be great, but this means clients of my
> code would have to have the same version of boost installed that we use,
> and I imagine this could cause conflicts in the event that they happen
> to use boost (and a different version of it). I'd rather not include
> more code dependencies than I absolutely have to, especially if they may
> prove problematic in the future. What do I do? I know I'm not the first
> in this situation. How often have others opted for this dependency as
> opposed to furnishing their own alternative that would avoid additional
> dependencies (at the expense of the benefit of time-tested code)?

One way around this is to include the boost libraries you require in
your own distribution with the top-level namespace appropriately
renamed. Yes, this is ugly, it means distributing the code and modifying
it so that all the namespaces are different.

e.g. boost::shared_ptr -> boost_1_38::shared_ptr

Within your own code you can use a namespace alias to make it easier to
move to new versions of boost as and when required.

e.g. namespace geoff_boost = boost_1_38;

Then use geoff_boost::* within your own code. You can then move your own
code to new versions of boost by changing that single alias.

Externally you can provide typedefs to smart_ptr classes.

e.g.
namespace package
{
        class foo;
        typedef geoff_boost::smart_ptr<foo> foo_ptr
}

So clients of the library deal with names like package::foo_ptr and have
no idea that behind the scenes you're using a specific version of boost
hidden behind a couple of namepsaces...

It's a trade-off - you have to do something nasty, but the client gets
to see nice names, you get to re-use solid code but you'll have to live
with the dirty feeling of modifying the boost headers (a perl script or
two, so you can do it automatically for a new version) and
re-distributing them.

   n
_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: Avoiding reinventing the wheel for a public api with binary compatibility in mind

by OvermindDL1 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Nov 4, 2009 at 6:52 PM, Nigel Rantor <wiggly@...> wrote:

> Geoff Hilton wrote:
>>
>> I'm writing a public api for a product which will be bundled as a
>> precompiled dll or binary and one of my goals is binary compatibility (if
>> not across major versions, at least across minor). I'd like to implement the
>> pimpl idiom and reference counting for the handle classes as appropriate,
>> but I'm worried about all the typical stuff (exception safety, memory leaks,
>> etc) and I'd rather not reinvent the wheel.
>>
>> eg.
>> template<typename T>
>> class MyClass {
>> public:
>> T foo();
>> private:
>> boost::shared_ptr<MyClassImpl<T> > impl;
>> };
>>
>> Using boost::shared_ptr would be great, but this means clients of my code
>> would have to have the same version of boost installed that we use, and I
>> imagine this could cause conflicts in the event that they happen to use
>> boost (and a different version of it). I'd rather not include more code
>> dependencies than I absolutely have to, especially if they may prove
>> problematic in the future. What do I do? I know I'm not the first in this
>> situation. How often have others opted for this dependency as opposed to
>> furnishing their own alternative that would avoid additional dependencies
>> (at the expense of the benefit of time-tested code)?
>
> One way around this is to include the boost libraries you require in your
> own distribution with the top-level namespace appropriately renamed. Yes,
> this is ugly, it means distributing the code and modifying it so that all
> the namespaces are different.
>
> e.g. boost::shared_ptr -> boost_1_38::shared_ptr
>
> Within your own code you can use a namespace alias to make it easier to move
> to new versions of boost as and when required.
>
> e.g. namespace geoff_boost = boost_1_38;
>
> Then use geoff_boost::* within your own code. You can then move your own
> code to new versions of boost by changing that single alias.
>
> Externally you can provide typedefs to smart_ptr classes.
>
> e.g.
> namespace package
> {
>        class foo;
>        typedef geoff_boost::smart_ptr<foo> foo_ptr
> }
>
> So clients of the library deal with names like package::foo_ptr and have no
> idea that behind the scenes you're using a specific version of boost hidden
> behind a couple of namepsaces...
>
> It's a trade-off - you have to do something nasty, but the client gets to
> see nice names, you get to re-use solid code but you'll have to live with
> the dirty feeling of modifying the boost headers (a perl script or two, so
> you can do it automatically for a new version) and re-distributing them.

The tool "bcp" that comes with boost can take out parts of Boost that
you want to include in your projects, and as I recall it can also
rename namespaces automatically (either that or it is a feature being
worked on).
_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: Avoiding reinventing the wheel for a public api with binary compatibility in mind

by Nigel Rantor :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

OvermindDL1 wrote:
> The tool "bcp" that comes with boost can take out parts of Boost that
> you want to include in your projects, and as I recall it can also
> rename namespaces automatically (either that or it is a feature being
> worked on).

Groovy. I remember hearing about it but didn't know it could do renaming
too.

   n
_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: Avoiding reinventing the wheel for a public api with binary compatibility in mind

by Gottlob Frege :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Nov 4, 2009 at 8:16 PM, Geoff Hilton
<geoff.hilton@...> wrote:
> I'm writing a public api for a product which will be bundled as a
> precompiled dll or binary and one of my goals is binary compatibility

> eg.
> template<typename T>
> class MyClass {
> public:
> T foo();
> private:
> boost::shared_ptr<MyClassImpl<T> > impl;
> };
>

Use boost::intrusive_ptr<> and make sure the intrusive_ptr_add_ref(T)
and intrusive_ptr_release(T) are implemented _inside_ your DLL.

Tony
_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: Avoiding reinventing the wheel for a public api with binary compatibility in mind

by Emil Dotchevski-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Nov 4, 2009 at 11:10 PM, Gottlob Frege <gottlobfrege@...> wrote:

> On Wed, Nov 4, 2009 at 8:16 PM, Geoff Hilton
> <geoff.hilton@...> wrote:
> > I'm writing a public api for a product which will be bundled as a
> > precompiled dll or binary and one of my goals is binary compatibility
> > template<typename T>
> > class MyClass {
> > public:
> > T foo();
> > private:
> > boost::shared_ptr<MyClassImpl<T> > impl;
> > };
>
> Use boost::intrusive_ptr<> and make sure the intrusive_ptr_add_ref(T)
> and intrusive_ptr_release(T) are implemented _inside_ your DLL.

That is about as stable binary interface as boost::shared_ptr.

Emil Dotchevski
Reverge Studios, Inc.
http://www.revergestudios.com/reblog/index.php?n=ReCode
_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: Avoiding reinventing the wheel for a public api with binary compatibility in mind

by Geoff Hilton :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

OvermindDL1 wrote:

> On Wed, Nov 4, 2009 at 6:52 PM, Nigel Rantor <wiggly@...> wrote:
>> Geoff Hilton wrote:
>>> I'm writing a public api for a product which will be bundled as a
>>> precompiled dll or binary and one of my goals is binary compatibility (if
>>> not across major versions, at least across minor). I'd like to implement the
>>> pimpl idiom and reference counting for the handle classes as appropriate,
>>> but I'm worried about all the typical stuff (exception safety, memory leaks,
>>> etc) and I'd rather not reinvent the wheel.
>>>
>>> eg.
>>> template<typename T>
>>> class MyClass {
>>> public:
>>> T foo();
>>> private:
>>> boost::shared_ptr<MyClassImpl<T> > impl;
>>> };
>>>
>>> Using boost::shared_ptr would be great, but this means clients of my code
>>> would have to have the same version of boost installed that we use, and I
>>> imagine this could cause conflicts in the event that they happen to use
>>> boost (and a different version of it). I'd rather not include more code
>>> dependencies than I absolutely have to, especially if they may prove
>>> problematic in the future. What do I do? I know I'm not the first in this
>>> situation. How often have others opted for this dependency as opposed to
>>> furnishing their own alternative that would avoid additional dependencies
>>> (at the expense of the benefit of time-tested code)?
>> One way around this is to include the boost libraries you require in your
>> own distribution with the top-level namespace appropriately renamed. Yes,
>> this is ugly, it means distributing the code and modifying it so that all
>> the namespaces are different.
>>
>> e.g. boost::shared_ptr -> boost_1_38::shared_ptr
>>
>> Within your own code you can use a namespace alias to make it easier to move
>> to new versions of boost as and when required.
>>
>> e.g. namespace geoff_boost = boost_1_38;
>>
>> Then use geoff_boost::* within your own code. You can then move your own
>> code to new versions of boost by changing that single alias.
>>
>> Externally you can provide typedefs to smart_ptr classes.
>>
>> e.g.
>> namespace package
>> {
>>        class foo;
>>        typedef geoff_boost::smart_ptr<foo> foo_ptr
>> }
>>
>> So clients of the library deal with names like package::foo_ptr and have no
>> idea that behind the scenes you're using a specific version of boost hidden
>> behind a couple of namepsaces...
>>
>> It's a trade-off - you have to do something nasty, but the client gets to
>> see nice names, you get to re-use solid code but you'll have to live with
>> the dirty feeling of modifying the boost headers (a perl script or two, so
>> you can do it automatically for a new version) and re-distributing them.
>
> The tool "bcp" that comes with boost can take out parts of Boost that
> you want to include in your projects, and as I recall it can also
> rename namespaces automatically (either that or it is a feature being
> worked on).


bcp sounds interesting but according to
http://www.boost.org/doc/libs/1_40_0/tools/bcp/bcp.html (which happens
to use boost::shared_ptr as an example), using it would pull in 274
header dependencies.

_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: Avoiding reinventing the wheel for a public api with binary compatibility in mind

by Gottlob Frege :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Nov 5, 2009 at 2:11 AM, Emil Dotchevski
<emildotchevski@...> wrote:
>>
>> Use boost::intrusive_ptr<> and make sure the intrusive_ptr_add_ref(T)
>> and intrusive_ptr_release(T) are implemented _inside_ your DLL.
>
> That is about as stable binary interface as boost::shared_ptr.
>

I can see shared_ptr internals changing, for example to make it more threadsafe.
I can't see intrusive_ptr changing - by its very nature its internals
are, well, external.

Tony
_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: Avoiding reinventing the wheel for a public api with binary compatibility in mind

by Nigel Rantor :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Geoff Hilton wrote:
>
> bcp sounds interesting but according to
> http://www.boost.org/doc/libs/1_40_0/tools/bcp/bcp.html (which happens
> to use boost::shared_ptr as an example), using it would pull in 274
> header dependencies.

I nearly replied to this yesterday.

I'm wondering what you mean here.

Are you saying:

a) Wow, that's a lot isn't it? Did I do something wrong?

b) Oh, cool. But look, it grabbed a lot of stuff.

c) Other

I don't have access right now to my dev box so I have no idea how many
dependencies you should expect to see being pulled in.

Regards,

   n
_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: Avoiding reinventing the wheel for a public api with binary compatibility in mind

by Emil Dotchevski-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sat, Nov 7, 2009 at 7:13 PM, Nigel Rantor <wiggly@...> wrote:

> Geoff Hilton wrote:
>> bcp sounds interesting but according to
>> http://www.boost.org/doc/libs/1_40_0/tools/bcp/bcp.html (which happens to
>> use boost::shared_ptr as an example), using it would pull in 274 header
>> dependencies.
> I'm wondering what you mean here.
> Are you saying:
> a) Wow, that's a lot isn't it? Did I do something wrong?
> b) Oh, cool. But look, it grabbed a lot of stuff.
> c) Other
> I don't have access right now to my dev box so I have no idea how many
> dependencies you should expect to see being pulled in.

If there is evidence that a boost library (or even header) includes
things that it shouldn't, a ticket should be filed. However note that
this has nothing to do with the number of ingluded header files.

Emil Dotchevski
Reverge Studios, Inc.
http://www.revergestudios.com/reblog/index.php?n=ReCode
_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users