我开发了一个为客户提供各种API的库。我们有多个限制,其中之一是我们应该尽可能避免导出类。当客户使用各种编译器时,这在某些平台上是一个问题,这些编译器可能以不同的方式命名。
出于这个原因,我们为客户提供接口(纯虚拟),这有效地隐藏了我们的实现。我们使用IUtfString* createUtfString()
等工厂方法将对象传递给客户端,destroyUtf8String(IUtfString* string)
通常与某些IUtfString* IUtfString::copy()
函数配对。
在某些地方,我们会调用IUtfString::release()
这样的调用,它也可以与销毁函数或{{1}}函数配对。
这种方法很有效,到目前为止一切都很好,但它对我而言看起来是如此。它完全避免了RAII并且只是重复使用来自C的不透明指针。是否有某种习惯用于自动销毁这些工厂创建的对象而无需导出大型对象? pimpl习惯用法可能有用,因为它会隐藏UtfString对象的大部分内容,但它仍然迫使我们通过库/ dll导出对象,我们希望避免这些对象。
我们内部有增强支持,但我们也避免将这些类型暴露给客户端。
答案 0 :(得分:1)
您可以尝试键入shared_ptr<IUtfString>
,然后更改createUtfString()
函数以返回具有自定义删除功能的实例。
类似
typedef boost::shared_ptr<IUtfString> UtfString;
/*does nothing now. Designed for code compatibility*/
void destroyUtfString( IUtfString* ) {}
UtfString createUtfString( ... ) {
return boost::shared_ptr<IUtfString>(oldCreateUtfString(),oldDestroyUtfString);
}
答案 1 :(得分:0)
如果您能够将实际的C ++类公开给客户端代码,那么只需像往常一样使用析构函数和复制构造函数。您仍然可以使用特殊的工厂函数来创建实例和返回指针,但是客户端将在这些指针上调用delete
而不是调用特殊的销毁函数,因此客户端可以使用标准的智能指针类来避免资源泄漏。
但是如果你试图避免C ++名称错位问题,那么你的库可能只暴露struct
和extern "C"
函数,而不是类。这意味着您的库确实有一个C API,即使它在内部使用C ++实现,并且您不能提供析构函数,因为您不能拥有extern "C"
析构函数。如果是这种情况,请认识到您提供的是C API,并且不必担心其缺乏C ++功能。
答案 2 :(得分:0)
我使用过类似的技巧。基本思想是你假设虚函数表比名称修改更稳定。
然后将您的功能导出为extern "C"
。
我要做的是创建仅包含头文件的包装器,将这些返回值包装在std::shared_ptr
或std::unique_ptr
中。并确保您不导出它们。他们会调用您的extern "C"
导出的函数。 (或boost
,或自己动手)
由于它们在标题中是inline
,因此它们会在&#34;客户端围栏中编译&#34;。因此版本和修改无关紧要!
这会在回调到您的API时强制客户端.get()
:但您可以使用更多仅包含智能指针的包装器和.get()
(或.release()
)来处理此问题。它们。
如果您有侵入式引用计数,那么shared_ptr
的驱逐程序可以将侵入计数减少一个:这会使原始指针传入并使shared_ptr
更加实用。