c++ - 将 void** 转换为 T** 的问题

标签 c++ casting

TL;DR:我有一个 Derived**,我在 Lua 中将其存储为 void* 用户数据。然后我试着把它作为一个 Base** 找回来,然后东西坏了。有什么我可以做的吗?还是这一切都是注定要失败的疯狂?

详细信息:

我在 Lua 和 C++ 之间来回传递一些数据,而 Lua 需要使用 void* 来存储用户数据(我正在使用 Lua 并不太重要,除了它使用 void 指针之外)。到目前为止是有道理的。假设我有三个类(class),BaseDerived , 与 Derived继承自 Base .我提供给 Lua 的用户数据是一个指向指针的指针,如下所示:

template <typename T>
void lua_push(L, T* obj) {
    T** ud = (T**)lua_newuserdata(L, sizeof(T*)); // Create a new userdata
    *ud = obj; // Set a pointer to my object
    // rest of the function setting up other stuff omitted
}

当然,这是一个很好的模板函数,所以我可以通过这种方式传递我的三种类型中的任何一种。稍后我可以使用另一个模板函数从 Lua 中获取我的用户数据,如下所示:

template <typename T>
T* lua_to(lua_State* L, int index) { 
    // there's normally a special metatable check here that ensures that 
    // this is the type I want, I've omitted it for this example
    return *(T**)lua_touserdata(L, index);
}

当我传入和传出相同的类型时,这工作正常。我在尝试拉出 Derived 时遇到了问题输出为 Base .

在我的具体情况下,我有一个 vector 存储在 Base 上.我用 lua_push<Derived>(L, obj);将我的对象推送到 Lua。后来,在另一个地方,我使用 Base* obj = lua_to<Base>(L, i); 将其拉出。 .然后我push_back一些东西到我的 vector 中。稍后,另一部分代码提取出完全相同的对象(通过指针比较验证),除了这次使用 Derived* obj = lua_to<Derived>(L, i);。我的Derived object 没有看到被插入的那个对象。我相信我已经将其缩小到不正确的转换,并且当我调用 push_back 时我可能在某处破坏了一些内存。

所以我的问题是,有没有办法让转换正常工作?我试过各种口味的类型转换。 static_cast、dynamic_cast 和 reinterpret_cast 似乎不起作用,要么给我同样的错误答案,要么根本不编译。

具体例子:

Base* b = lua_to<Base>(L, -1); // Both lua_to's looking at the same object
Derived* d = lua_to<Derived>(L, -1); // You can be double sure because the pointers in the output match
std::cout << "Base: " << b << " " << b->myVec.size() << std::endl;
std::cout << "Derived: " << d << " " << d->myVec.size() << std::endl;

输出:

Base: 0xa1fb470 1
Derived: 0xa1fb470 0

最佳答案

代码不安全。当您将 Base * 转换为 void * 时,您应该始终首先将 void * 转换回 Base * 并且 < em>然后 再次将其转换为 Derived *。这样:

Derived *obj = ...;
Base** ud = reinterpret_cast<Base **>(lua_newuserdata(L, sizeof(Base*)));
*ud = obj; // implicit cast Derived -> Base
...
Derived *obj = static_cast<Derived *>(*ud); // explicit Base -> Derived

一般来说,

Y -> X -> void* -> X -> Y (safe)
Y -> X -> void* -> Y (unsafe)

这是因为如果两个指针的类型不同,指向同一个对象的两个指针的实际指针值可能不同。它是否起作用取决于继承和虚函数等各种因素。 (它总是在 C 中工作,因为 C 没有这些设施。)

关于c++ - 将 void** 转换为 T** 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6936299/

相关文章:

c++ - Dijkstra 算法中的优先级队列

C# 调用重载函数时自动转换

javascript - Node.JS/Javascript - 将字符串转换为整数会返回 NaN,而我不希望它返回

c - 使用 %d 与 %ld 打印 pid,linux

c - 在 C 中为非空 void* 指针赋值的正确方法应该是什么?

c++ - 从模板参数继承并在 C++ 中向上转换

c++ - 如何将实际的 sf::Sprite 对象保存在数组或 vector 中? C++

c++ - 这些指针中的哪一个需要 free() 或 delete()

c++ - 初始化utf8编码字符串c++11

c++ - 为什么 qi::skip 会因来自词法分析器的标记而失败?