我的库如何让用户灵活选择他们的智能指针实现?
我正在创建一个 C++ 库,它在公共接口和内部都大量使用智能指针。目前它是“仅标头”,但随着它的发展,很明显这可能不合适。
我不想向库用户规定智能指针实现的选择。我在没有引入任何依赖项(例如 boost)的情况下也取得了很大的进展,并且希望尽可能长时间地保持无依赖项。该库不针对 c++0x,并且(毫不奇怪)希望尽可能保持符合标准。
目前,我让用户选择实现的解决方案如下所示:
#ifndef MYLIB_MEMORY_H_
#define MYLIB_MEMORY_H_
#if MYLIB_STD_SMART_PTR
#include <memory>
#define MYLIB_SHARED_PTR std::shared_ptr
#define MYLIB_WEAK_PTR std::weak_ptr
#define MYLIB_STATIC_POINTER_CAST std::static_pointer_cast
#elif MYLIB_STD_TR1_SMART_PTR
#include <tr1/memory>
#define MYLIB_SHARED_PTR std::tr1::shared_ptr
#define MYLIB_WEAK_PTR std::tr1::weak_ptr
#define MYLIB_STATIC_POINTER_CAST std::tr1::static_pointer_cast
#elif MYLIB_BOOST_SMART_PTR
#include <boost/shared_ptr.hpp>
#define MYLIB_SHARED_PTR boost::shared_ptr
#define MYLIB_WEAK_PTR boost::weak_ptr
#define MYLIB_STATIC_POINTER_CAST boost::static_pointer_cast
#else
#error Please define one of MYLIB_STD_SMART_PTR, MYLIB_STD_TR1_SMART_PTR or MYLIB_BOOST_SMART_PTR
#endif
#endif // MYLIB_MEMORY_H_
由于该库当前仅包含头文件,因此在(客户端)编译时选择宏就足够了。我担心如果我转移到共享库,这个技巧就会失效,我将不得不寻找另一种方法。
那另一种方式可能是什么?
I'm creating a c++ library that makes heavy use of smart pointers, both in public interface and internally. Currently it is "header-only", but as it evolves it is becoming clear that this may not be appropriate.
I don't want to dictate a choice of smart pointer implementation to library users. I also have gotten pretty far without bringing in any dependencies (such as boost), and would like to stay dependency-free as long as possible. The library isn't targeting c++0x, and (unsurprisingly) wants to stay as standards-compliant as possible.
Currently, my solution for letting users select an implementation looks like this:
#ifndef MYLIB_MEMORY_H_
#define MYLIB_MEMORY_H_
#if MYLIB_STD_SMART_PTR
#include <memory>
#define MYLIB_SHARED_PTR std::shared_ptr
#define MYLIB_WEAK_PTR std::weak_ptr
#define MYLIB_STATIC_POINTER_CAST std::static_pointer_cast
#elif MYLIB_STD_TR1_SMART_PTR
#include <tr1/memory>
#define MYLIB_SHARED_PTR std::tr1::shared_ptr
#define MYLIB_WEAK_PTR std::tr1::weak_ptr
#define MYLIB_STATIC_POINTER_CAST std::tr1::static_pointer_cast
#elif MYLIB_BOOST_SMART_PTR
#include <boost/shared_ptr.hpp>
#define MYLIB_SHARED_PTR boost::shared_ptr
#define MYLIB_WEAK_PTR boost::weak_ptr
#define MYLIB_STATIC_POINTER_CAST boost::static_pointer_cast
#else
#error Please define one of MYLIB_STD_SMART_PTR, MYLIB_STD_TR1_SMART_PTR or MYLIB_BOOST_SMART_PTR
#endif
#endif // MYLIB_MEMORY_H_
Since the library is currently header-only, choosing a macro at (client) compile time is sufficient. I'm afraid that if I move to a shared library, this trick will break down and I'll have to find another way.
What might that other way be?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
不是答案
我会采取不同的方法来选择共享指针,主要是因为我不喜欢宏。
现在,关于实际问题,如果智能指针用作库中编译的公共接口的一部分,您将必须提供不同的二进制文件,并让用户选择要链接的二进制文件。话又说回来,我会尝试避免在库的 API 中使用
shared_ptr
,因为它强制您对用户的智能指针选择(当然,除非您的库确实与客户端共享指针),而是使用std::auto_ptr
,它的优点是能够自动管理内存,同时允许用户决定将资源移动到任何通过调用release()来获取其他类型的指针(一旦shared_ptr获得资源的所有权,它就无法归还所有权)。Not an answer
I would take a different approach to the selection of the shared pointer, mainly because I dislike macros.
Now, relating to the actual question, if the smart pointers are used as part of the public interface of a compiled in library you will have to provide different binaries and have the user pick which binary to link against. Then again, I would try avoiding the use of
shared_ptr
in the API of a library, as it forces your choice of smart pointer onto your users (unless, of course, your library does share the pointers with the clients), and rather usestd::auto_ptr
that has the advantage of being able to manage the memory automatically and at the same time allow the user to decide to move the resource to any other type of pointer by callingrelease()
(once ashared_ptr
obtains ownership of a resource, it cannot give ownership back).我认为您的图书馆拥有的对象(您的图书馆负责其销毁)应该以您认为合适的任何方式保存。不属于您的库的对象的销毁方法应该留给客户端来决定(这意味着您可能应该只获得一个常规指针)。
现在我们只剩下具有共享所有权的对象(例如shared_ptr或一些其他引用计数对象)。您在这里可以做的是为每个引用计数的对象获取回调以减少其引用计数。您可以决定固定签名,并且客户端始终可以在需要时使用适配器。
I think that objects that are owned by your library (your library is responsible for its destruction) should be kept in any way you see fit. Destruction method of objects that are not owned by your library should be left for the client to decide (meaning you should probably just get a regular pointer).
Now we are left with objects that have shared ownership (e.g. shared_ptr or some other reference counted objects). What you can do here is get a call back for each referenced counted object for decreasing its reference count. You can decide on a fixed signature and the client can always use an adapter when needed.
这些宏共享指针类型是否出现在您的库的 API 中?
如果是这样,那么您就会遇到问题,因为即使在单个实现中,boost::shared_ptr 和 std::shared_ptr 也可能是不同的类型。除非共享的两个人使用相同的
shared_ptr
,否则您无法共享对象的所有权,因此您必须选择一个。可能是boost::shared_ptr
,并将 Boost 的这一部分与您的库标头一起提供。这就是 bcp 的用途。如果没有,那么这个技巧仍然有效——如果用户自己编译你的库,那么他们可以选择一个(或者我想你可以自动配置它)。如果你编译你的库并发布二进制文件,使用你喜欢的任何东西,它不会引入任何不存在的 dll 依赖项。
如果它当前是界面的一部分,但不需要是因为您的库实际上并不与用户共享所有权,那么您可以尝试更改界面。例如,当返回新分配的对象时,不要返回
shared_ptr
,而是返回auto_ptr
。当然,它在 C++11 中已被弃用,但至少它存在,这比任何其他智能指针和 C++03 都更重要。然后,您的用户可以立即转换为他们选择的合适的智能指针。Do these macro-ed shared pointer types appear in the API to your library?
If so, then you have a problem, since even in a single implementation
boost::shared_ptr
andstd::shared_ptr
may be different types. You can't share ownership of an object unless the two people sharing use the sameshared_ptr
, so you have to pick one. Probablyboost::shared_ptr
, and ship that part of Boost with your library headers. This is whatbcp
is for.If not, then the trick continues to work -- if users compile your library for themselves then they can pick one (or I suppose you could autoconf it). If you compile your library and ship binaries, use whatever you like, it won't introduce any dll dependencies that weren't there already.
If it's currently part of the interface, but it doesn't need to be because your library doesn't actually share ownership with the user, then you could try changing the interface. For example, when returning a newly-allocated object, don't return
shared_ptr
, returnauto_ptr
instead. Sure, it's deprecated in C++11, but at least it exists, which is more than can be said for any other smart pointer and C++03. Your user can then immediately convert to a proper smart pointer of their choice.您仍然可以使用这样的方法,只需将选择移到用户编译您的库时而不是编译自己的代码时即可。然后在标头中提供一些适当的 typedef,以公开正确的类型,而无需丑陋的宏。
这样,您还可以避免使用与用户安装的版本不兼容的
boost::shared_ptr
版本来编译库代码的问题。或者标准库的不同版本,或者其他什么。You can still use such a method, just move the chose to when the user compiles your library rather than when they compile their own code. Then provide some appropriate
typedef
s in the headers that expose the correct types without the ugly macros.This way, you also circumvent the issue of your library code being compiled with a version of
boost::shared_ptr
incompatible with the version the user has installed. Or a different version of the standard library, or whatever.