[英]Static libraries and shared objects, are symbols shared?
我正在创建一个帮助程序,以在C ++类和Lua对象之间创建多个继承。 因为Lua将C / C ++用户对象存储为void *,所以在检索对象时很难进行安全的强制转换。
例如,
如果你有
class A { }
class B { }
class C : public A, public B { }
然后将C类型的对象传递给Lua,传递C实例的地址,当需要将其强制转换为B时,C ++编译器会自动将指针对准B在C中的位置,因此这是不安全的直接将void *指针从C强制转换为B。
为避免此问题,我使用了一种转换器。 在Lua中,对象包含其名称作为字符串,因此,当您需要将对象从类型转换为其他类型时,它使用如下转换器:
converters [“ B”] [“ C”](mypointer,myresultpointer);
这是帮助创建这些转换器的类:
// Common.h
#include <functional>
#include <memory>
#include <unordered_map>
#include <string>
typedef std::function<void (void *, void *)> LuaConverter;
typedef std::unordered_map<
std::string,
std::unordered_map<
std::string,
LuaConverter
>
> LuaConverters;
class LuaeClass {
public:
static LuaConverters converters;
public:
template <class From, class To>
static void createConverter(const std::string &fromName,
const std::string &toName)
{
converters[toName][fromName] = [&] (void *ptr, void *result) -> void {
std::shared_ptr<From> *from = static_cast<std::shared_ptr<From> *>(ptr);
*((std::shared_ptr<To> *)result) = std::static_pointer_cast<To>(*from);
};
}
};
此类被编译为静态库,以在项目中多次使用。
对象需要作为shared_ptr传递(它还解决了所有权和删除问题)。 它运作良好,但是当用作静态库时会出现段错误。
然后,我有一个简单的模块Battery,被编译为共享对象并链接到公共库。
在示例的范围内,它没有太多功能,但实际上使用了LuaeClass:
// Battery.cpp
#include <lua.hpp>
#include "Common.h"
class Battery {
public:
int getPercent() {
return 100;
}
};
extern "C" int luaopen_battery(lua_State *L)
{
LuaeClass::createConverter<Battery, Battery>("Battery", "Battery");
return 0;
}
这被编译为名为Battery.so的共享对象,Lua将使用dlopen()和dlcose()进行加载。
最后,主要。 它还链接到common并使用它来创建对象。
// main.cpp
#include <iostream>
#include <memory>
#include <string>
#include <lua.hpp>
#include "Common.h"
using namespace std;
class LuaDeleter {
public:
void operator()(lua_State *L) {
lua_close(L);
}
};
typedef unique_ptr<lua_State, LuaDeleter> LuaState;
int main(void)
{
LuaState L(luaL_newstate());
luaL_requiref(L.get(), "_G", luaopen_base, 1);
luaL_requiref(L.get(), "package", luaopen_package, 1);
// This will dlopen() and dlclose()
string code = "local battery = require \"battery\"";
LuaeClass::createConverter<int, int>("Int", "Int");
if (luaL_dostring(L.get(), code.c_str()) != LUA_OK) {
cerr << lua_tostring(L.get(), -1) << endl;
}
return 0;
}
总结一下:
出口处的主要段错误,核心文件说它在std :: function <>的析构函数中,所以我猜它在同一指针上被多次调用,对吗?
静态库数据是否在所有代码中共享? 如何避免这个问题?
核心的开始
#0 0x0000000000404062 in std::__1::function<void (void*, void*)>::~function() ()
#1 0x0000000000404025 in std::__1::function<void (void*, void*)>::~function() ()
下一个跟踪是不可读和不可用的。
静态库的代码和全局/静态数据将注入到链接它的每个模块中。 因此,对于您的情况,项目中存在多个LuaeClass::converters
实例。 并且您需要在每个链接静态库的模块中调用luaopen_battery()
。
我不确定您的崩溃是否与静态链接有关,但是我很确定您使用了复杂的实现。
您要解决的第一个问题是将void*
安全地转换为A*, B*, C*
。 您要导出到Lua的哪个类/接口? 如果是class C
,则可以在C类中定义以下方法:
void pushThis(lua_State *L);
static C* getThis(lua_State *L, int idx);
两种方法都使用C*
,因此您不需要转换函数。 您可以使用元表将指针与其他用户数据区分开 。 如果您需要B*
,只需:
B* b = (B*)C::getThis(L, idx);
而且,您可能不一定需要shared_ptr。 当GC收集您的Lua对象时,shared_ptr不能帮助您删除C ++对象(因为shared_ptr仍然存在于堆中)。 相反,您必须在元表中实现__gc
回调才能删除对象 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.