0

C++ クラスと Lua オブジェクト間の多重継承を作成するヘルパーを作成しています。Lua は C/C++ ユーザー オブジェクトを void * として格納するため、オブジェクトを取得するときに安全なキャストを行うのは困難です。

例えば、

あなたが持っている場合

class A { }
class B { }
class C : public A, public B { }

そして、タイプ C のオブジェクトを Lua に渡し、C インスタンスのアドレスを渡します。それを B にキャストする必要がある場合、C++ コンパイラはポインターを C の B の位置に自動的に揃えるので、安全ではありません。 void * ポインターを C から B に直接キャストします。

この問題を回避するために、一種のコンバーターを使用します。Lua では、オブジェクトには文字列として名前が含まれているため、オブジェクトを型から別の型にキャストする必要がある場合は、次のようにコンバーターを使用します。

コンバーター["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() を使用してロードします。

最後にメイン。共通にもリンクし、それを使用してオブジェクトを作成します。

// 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;
}

要約すると:

  • Common.cpp、Common.h は単純な静的ライブラリ (libcommon.a) としてコンパイルされます。
  • Main.cpp、コンパイル済み、libcommon.a へのリンク
  • 共有オブジェクトおよび libcommon.a へのリンクとしてコンパイルされた Battery.cpp

終了時のメインのセグメンテーション違反、コア ファイルはそれが std::function<> のデストラクタにあると言っているので、同じポインタで複数回呼び出されていると思いますか?

スタティック ライブラリ データはすべてのコードで共有されていますか? この問題を回避するにはどうすればよいですか?

コアの始まり

#0  0x0000000000404062 in std::__1::function<void (void*, void*)>::~function() ()
#1  0x0000000000404025 in std::__1::function<void (void*, void*)>::~function() ()

次のトレースは、読み取り不能で使用不能です。

4

1 に答える 1