You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C++中用sol2嵌入Lua时shared_ptr传参异常问题

Sol2嵌入Lua时std::shared_ptr参数传递异常解决方法

问题重现

在C++项目中使用sol2嵌入Lua开发,SceneNode类的addChild函数接收std::shared_ptr<SceneNode>参数,但Lua脚本调用时抛出类型不匹配异常,核心错误提示:

sol: 运行时错误: 栈索引2,期望userdata,接收到sol.SceneNode: 值是userdata但不是正确的唯一usertype(参数传入'std::shared_ptr(std::shared_ptr)'失败)

相关代码

C++ addChild函数

std::shared_ptr<SceneNode> SceneNode::addChild(std::shared_ptr<SceneNode> child)
{
    child->setParent(std::weak_ptr(shared_from_this()));
    children.push_back(child);

    return child;
}

Lua环境初始化代码

void setup_lua() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua.new_usertype<SceneNode>("SceneNode",
        sol::constructors<
            void(),
            void(std::string)>(),
            //sol::base_classes, sol::bases<std::enable_shared_from_this<SceneNode>>(),
            "id", &SceneNode::id,
            "name", &SceneNode::name,
            "addChild", &SceneNode::addChild
        );

    lua.script_file("/Path/to/setup_lua.lua");
}

Lua脚本代码

local node = SceneNode:new("node")
print(node.name)
print(node.id)

local childNode = SceneNode:new("child")
node:addChild(childNode)
print(childNode.name)
print(childNode.id)

print(node)
print(childNode)

完整报错信息

node
-2472761803519894154
[sol2] 发生错误并已传递给错误处理程序: sol: 运行时错误: 栈索引2,期望userdata,接收到sol.SceneNode: 值是userdata但不是正确的唯一usertype(参数传入'std::shared_ptr<SceneNode>(std::shared_ptr<SceneNode>)'失败)
stack traceback:
        [C]: in method 'addChild'
        /Path/to/setup_lua.lua:13: in main chunk
terminate called after throwing an instance of 'sol::error'
  what():  sol: 运行时错误: 栈索引2,期望userdata,接收到sol.SceneNode: 值是userdata但不是正确的唯一usertype(参数传入'std::shared_ptr<SceneNode>(std::shared_ptr<SceneNode>)'失败)
stack traceback:
        [C]: in method 'addChild'
        /Path/to/setup_lua.lua:13: in main chunk
Aborted (core dumped)

原因分析

sol2默认会将SceneNode作为值类型注册到Lua中,Lua中创建的SceneNode实例是直接存储的原始对象,而非std::shared_ptr<SceneNode>包装的对象。但addChild函数期望接收std::shared_ptr<SceneNode>类型参数,两者类型不匹配导致转换失败。

另外你注释掉了sol::base_classes相关代码,而SceneNode继承了std::enable_shared_from_this<SceneNode>,sol2需要识别这个基类才能正确处理shared_ptr的自动转换。

解决方法

修改Lua环境初始化代码,取消注释sol::base_classes相关行,让sol2识别SceneNode的enable_shared_from_this基类,从而自动用std::shared_ptr管理Lua中的实例:

void setup_lua() {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    lua.new_usertype<SceneNode>("SceneNode",
        sol::constructors<
            void(),
            void(std::string)>(),
            sol::base_classes, sol::bases<std::enable_shared_from_this<SceneNode>>(),
            "id", &SceneNode::id,
            "name", &SceneNode::name,
            "addChild", &SceneNode::addChild
        );

    lua.script_file("/Path/to/setup_lua.lua");
}

如果不想依赖enable_shared_from_this,也可以直接注册std::shared_ptr<SceneNode>作为Lua中的usertype,手动绑定成员:

lua.new_usertype<std::shared_ptr<SceneNode>>("SceneNode",
    sol::constructors<std::shared_ptr<SceneNode>(), std::shared_ptr<SceneNode>(std::string)>(),
    "id", [](const std::shared_ptr<SceneNode>& self) { return self->id; },
    "name", [](const std::shared_ptr<SceneNode>& self) { return self->name; },
    "addChild", [](std::shared_ptr<SceneNode>& self, std::shared_ptr<SceneNode> child) {
        return self->addChild(child);
    }
);

第一种方法更简洁,因为SceneNode已经继承enable_shared_from_this,sol2会自动处理shared_ptr的创建与转换,Lua中通过SceneNode:new()创建的实例会被自动包装为std::shared_ptr,调用addChild时就能正确匹配参数类型。


内容的提问来源于stack exchange,提问作者Yaene

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 11:37:11