C++ 返回shared_ptr引用的方法如何在参数无效时返回空值?
现有基于静态空shared_ptr的实现功能可用,但存在隐藏风险:每个模板实例对应的静态空shared_ptr<T>是全局共享的可变实例,若业务代码意外修改了无效参数场景下返回的该实例(如调用reset、赋值新对象),后续所有同类型的无效参数调用都会拿到被篡改的错误值,排查成本极高。
以下是可落地的优化方案,按推荐优先级排序:
方案1:非法参数直接触发Lua错误(最优)
Lua绑定场景下传入不符合类型要求的参数本身属于非法调用,常规处理逻辑是直接抛出Lua错误终止执行,不需要返回容错值,既完美解决返回引用的两难问题,也能第一时间暴露参数传错的问题:
template<class T> static shared_ptr<T>& getSharedPtr(lua_State* L, int32_t arg) { if (!is<T>(L, arg)) { luaL_error(L, "argument %d is not a valid %s userdata", arg, typeid(T).name()); } return *static_cast<shared_ptr<T>*>(lua_touserdata(L, arg)); }
luaL_error执行后不会返回,无需处理返回值问题,原有业务代码无需任何修改即可兼容。
方案2:拆分读写接口+编译期保护
如果确实需要容错不抛出错误,可以拆分读写两个接口,从语法层面规避静态实例被篡改的风险:
// 只读场景调用,返回const引用禁止修改 template<class T> static const shared_ptr<T>& getSharedPtr(lua_State* L, int32_t arg) { if (!is<T>(L, arg)) { static const shared_ptr<T> shared_empty; return shared_empty; } return *static_cast<shared_ptr<T>*>(lua_touserdata(L, arg)); } // 需要修改shared_ptr(如reset、赋值)时调用,无效参数直接报错 template<class T> static shared_ptr<T>& getMutableSharedPtr(lua_State* L, int32_t arg) { luaL_argcheck(L, is<T>(L, arg), arg, "invalid userdata for mutable access"); return *static_cast<shared_ptr<T>*>(lua_touserdata(L, arg)); }
方案3:返回shared_ptr<T>指针(最小改造成本)
如果不想拆分接口,可以调整返回值为指针,无效时返回nullptr,调用语法改动极小,也不会增加额外引用计数:
template<class T> static shared_ptr<T>* getSharedPtr(lua_State* L, int32_t arg) { if (!is<T>(L, arg)) { return nullptr; } return static_cast<shared_ptr<T>*>(lua_touserdata(L, arg)); }
调用时仅需多一层空判断,语法和原有写法基本一致,不需要额外调用get()方法:
int32_t luaADelete(lua_State* L) { auto a = getSharedPtr<A>(L, 1); if (a && *a) { a->reset(); } return 0; }
内容的提问来源于stack exchange,提问作者MillhioreBT
相关产品推荐
相关产品推荐

