如何在 returns 共享指针的外语和 C++ 库之间进行接口
How to interface between a foreign language and a C++ library which returns shared pointers
我正在编写一个库,它在 kdb+ 之间进行接口(尽管这个问题通常适用于外语接口)和一个 C++ 库,其中大多数 API 调用 return std::shared_ptr
。当使用 kdb+ 与大多数库交互时,通常使用库的 API 创建对象,然后 return 它们的原始指针作为 long long
以便 kdb+ 程序员可以将对象发送回他们选择的图书馆。
共享指针使这变得困难。最小示例:
extern "C" K k_new_foo() {
// not using auto for the sake of clarity in the example
std::shared_ptr<library::Foo> ptr = library::Foo::Create();
// return the raw pointer as a long long int in a kdb object
return kj(reinterpret_cast<long long>(ptr.get()));
}
// ptr goes out of scope -> the library::Foo is freed prematurely
我想知道的是,是否有某种方法可以无限期地延长 std::shared_ptr
的生命周期,或者以其他方式防止破坏它指向的数据,直到程序员手动从内部释放它kdb+ 使用对该接口库的另一个调用。我很清楚我的要求违背了使用智能指针的目的;我很想知道一种 好的 方法来处理这个问题,如果这样的事情存在并且是实用的。
延长此类共享对象生命周期的唯一方法是将 shared_ptr
存储在内存中,直到不再需要该共享对象为止。
例如,你可以 new
一个单独的 std::shared_ptr
和 return 到外语,然后 delete
当你用完它时:
using Foo_sharedptr = std::shared_ptr<library::Foo>;
extern "C" K k_new_foo() {
Foo_sharedptr ptr = library::Foo::Create();
Foo_sharedptr *ptr2 = new Foo_sharedptr(ptr);
return kj(reinterpret_cast<J>(ptr2));
}
extern "C" void k_free_foo(K foo) {
delete reinterpret_cast<Foo_sharedptr*>(foo->j);
r0(foo);
}
或者,您可以将 shared_ptr
存储在您拥有的全局容器中,然后传递引用其元素的值:
using Foo_ptr = library::Foo*;
using Foo_sharedptr = std::shared_ptr<library::Foo>;
using FooMap = std::map<Foo_ptr, Foo_sharedptr>;
static FooMap g_foos;
// wrapped with a std::mutex if you need multithread safety...
extern "C" K k_new_foo() {
Foo_sharedptr foo = library::Foo::Create();
Foo_ptr ptr = foo.get();
g_foos[ptr] = foo;
return kj(reinterpret_cast<J>(ptr));
}
extern "C" void k_free_foo(K foo) {
Foo_ptr ptr = reinterpret_cast<Foo_ptr>(foo->j);
FooMap::iterator iter = g_foos.find(ptr);
if (iter != g_foos.end()) g_foos.erase(iter);
r0(foo);
}
我明白你的意思,不得不经历那是一团糟。
让我假设您不仅有一个新方法,而且还有一个显式删除方法。在这种情况下,您可以分配 shared_ptr.
extern "C" K k_new_foo() {
// not using auto for the sake of clarity in the example
std::shared_ptr<library::Foo> ptr = library::Foo::Create();
// return the raw pointer as a long long int in a kdb object
return kj(reinterpret_cast<long long>(new std::shared_ptr<library::Foo>(ptr)));
}
extern "C" void k_delete_foo(K k) {
delete reinterpret_cast<std::shared_ptr<library::Foo> *>(k.foo));
}
extern "C" void k_thread_foo(K k) {
auto &ptr = *reinterpret_cast<std::shared_ptr<library::Foo> *>(k.foo));
std::thread{[ptr]{ /* Do something */ }}.detach();
}
当然,这不是一种好的编码方式。但是,它确实允许您为所有 C++ 代码保留 shared_ptr
,同时在从另一种语言错误使用时可能有内存 leaks/ub。
如果你想防止不正确的使用。您可以改为将所有指针收集在某种全局变量中。这样,您可以首先检查该指针是否共享给其他语言。除了传递新的 shared_ptr,您可以与其共享原始指针,并且行为可能会变得更加明确,因为在退出时,将调用所有析构函数。缺点包括更多的簿记,这将作为性能损失而引人注目。
如果您只想将所有权附加到您传递的原始指针,而没有这样的删除方法,我只能建议您通过将所有内容收集到一个全局向量中来进行某种内存泄漏。
您可以做的是在您的界面中维护一个 shared_ptr<Foo>
的容器。您的 k_new_foo
函数将在该容器中保存 shared_ptr 的副本。然后 k_delete_foo
函数将从容器中删除 shared_ptr。
如果有太多不同的对象类型需要跟踪,这将不起作用。
我正在编写一个库,它在 kdb+ 之间进行接口(尽管这个问题通常适用于外语接口)和一个 C++ 库,其中大多数 API 调用 return std::shared_ptr
。当使用 kdb+ 与大多数库交互时,通常使用库的 API 创建对象,然后 return 它们的原始指针作为 long long
以便 kdb+ 程序员可以将对象发送回他们选择的图书馆。
共享指针使这变得困难。最小示例:
extern "C" K k_new_foo() {
// not using auto for the sake of clarity in the example
std::shared_ptr<library::Foo> ptr = library::Foo::Create();
// return the raw pointer as a long long int in a kdb object
return kj(reinterpret_cast<long long>(ptr.get()));
}
// ptr goes out of scope -> the library::Foo is freed prematurely
我想知道的是,是否有某种方法可以无限期地延长 std::shared_ptr
的生命周期,或者以其他方式防止破坏它指向的数据,直到程序员手动从内部释放它kdb+ 使用对该接口库的另一个调用。我很清楚我的要求违背了使用智能指针的目的;我很想知道一种 好的 方法来处理这个问题,如果这样的事情存在并且是实用的。
延长此类共享对象生命周期的唯一方法是将 shared_ptr
存储在内存中,直到不再需要该共享对象为止。
例如,你可以 new
一个单独的 std::shared_ptr
和 return 到外语,然后 delete
当你用完它时:
using Foo_sharedptr = std::shared_ptr<library::Foo>;
extern "C" K k_new_foo() {
Foo_sharedptr ptr = library::Foo::Create();
Foo_sharedptr *ptr2 = new Foo_sharedptr(ptr);
return kj(reinterpret_cast<J>(ptr2));
}
extern "C" void k_free_foo(K foo) {
delete reinterpret_cast<Foo_sharedptr*>(foo->j);
r0(foo);
}
或者,您可以将 shared_ptr
存储在您拥有的全局容器中,然后传递引用其元素的值:
using Foo_ptr = library::Foo*;
using Foo_sharedptr = std::shared_ptr<library::Foo>;
using FooMap = std::map<Foo_ptr, Foo_sharedptr>;
static FooMap g_foos;
// wrapped with a std::mutex if you need multithread safety...
extern "C" K k_new_foo() {
Foo_sharedptr foo = library::Foo::Create();
Foo_ptr ptr = foo.get();
g_foos[ptr] = foo;
return kj(reinterpret_cast<J>(ptr));
}
extern "C" void k_free_foo(K foo) {
Foo_ptr ptr = reinterpret_cast<Foo_ptr>(foo->j);
FooMap::iterator iter = g_foos.find(ptr);
if (iter != g_foos.end()) g_foos.erase(iter);
r0(foo);
}
我明白你的意思,不得不经历那是一团糟。
让我假设您不仅有一个新方法,而且还有一个显式删除方法。在这种情况下,您可以分配 shared_ptr.
extern "C" K k_new_foo() {
// not using auto for the sake of clarity in the example
std::shared_ptr<library::Foo> ptr = library::Foo::Create();
// return the raw pointer as a long long int in a kdb object
return kj(reinterpret_cast<long long>(new std::shared_ptr<library::Foo>(ptr)));
}
extern "C" void k_delete_foo(K k) {
delete reinterpret_cast<std::shared_ptr<library::Foo> *>(k.foo));
}
extern "C" void k_thread_foo(K k) {
auto &ptr = *reinterpret_cast<std::shared_ptr<library::Foo> *>(k.foo));
std::thread{[ptr]{ /* Do something */ }}.detach();
}
当然,这不是一种好的编码方式。但是,它确实允许您为所有 C++ 代码保留 shared_ptr
,同时在从另一种语言错误使用时可能有内存 leaks/ub。
如果你想防止不正确的使用。您可以改为将所有指针收集在某种全局变量中。这样,您可以首先检查该指针是否共享给其他语言。除了传递新的 shared_ptr,您可以与其共享原始指针,并且行为可能会变得更加明确,因为在退出时,将调用所有析构函数。缺点包括更多的簿记,这将作为性能损失而引人注目。
如果您只想将所有权附加到您传递的原始指针,而没有这样的删除方法,我只能建议您通过将所有内容收集到一个全局向量中来进行某种内存泄漏。
您可以做的是在您的界面中维护一个 shared_ptr<Foo>
的容器。您的 k_new_foo
函数将在该容器中保存 shared_ptr 的副本。然后 k_delete_foo
函数将从容器中删除 shared_ptr。
如果有太多不同的对象类型需要跟踪,这将不起作用。