C++ 中的 POD 和 VPtr 设计编译器
这个问题更多的是关于语言设计,而不是关于改变 C++ 约定。
在思考 Go 编程语言(它如何清理将数据与接口分离,有效地将所有对象转换为结构)和 C++ 中的 POD 时(在分配大量类似结构的小对象时,我喜欢 memset/memcpy),我想知道 C++ 编译器约定将 vptr 直接附加到对象的实例,搞砸了布局。
这是一个要求还是只是一个约定?
如果您正在设计替代编译器,您是否可以为 vptr 提供一个大型外部查找表?例如,像 map
?所有实例都将是 POD,就内存设置而言,为了查找其 vptr,我们将获取其地址并查看大型外部查找表。
缺点是,一切都需要查找。这是一个可行的替代设计还是有严重的缺点?
This question is more about language design and less about changing C++ conventions.
While thinking about the Go programming language (how it cleaning separates the data from the interfaces, effectively turning all objects into structs) and PODs in C++ (I like memset/memcpy when allocating a gazillion small struct-like objects), I was wondering about the C++ compiler convention of attaching a vptr directly to an instance of an object, messing up the layout.
Is this a requirement or just a convention?
If you were designing an alternative compiler, could you, instead, have a large external look-up table for vptrs? For example, a structure like map<void*,vptr>
? All instances would be POD, with respect to memory setting, and to look up its vptr, we would take its address and look inside the large external lookup table.
The disadvantage is, everything would require a lookup. Is this a viable alternative design or are there serious drawbacks?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
性能很可能会受到影响。某些语言为方法查找添加某种缓存。
您可以采用不同的方式来查找调用给定选择器(或方法名称)的方法。查看 Smalltalk 或 自己 或 Javascript 或 <一个href="http://en.wikipedia.org/wiki/Common_Lisp_Object_System" rel="nofollow">Common Lisp 对象系统 或 Ocaml
然而,某些语言的实现包含巧妙的技巧(缓存、JIT...),使它们与 C++ 一样快(但这是一个实现问题,而不是一种语言设计 问题)。
Performance will very probably suffer. Some languages add some kind of caching for method lookup.
You could have a different way of finding the method to call for a given selector (or method name). Look at Smalltalk or Self or Javascript or Common Lisp Object system or Ocaml
However, some languages implementation contains clever tricks (caching, JIT, ...) making them as fast as C++ (but it is an implementation issue, not a language design issue).
该映射必须存储那些可能是
vptr
大小的void*
指针,因此实际上使用了更多内存,因为vptr
将具有也可以存储起来。地图查找并不是微不足道的 - 如果发生碰撞,您必须执行线性搜索,直到找到精确匹配。因此,平均而言,查找速度会更慢,并且会使用更多内存。实际上,在对象前面添加
vptr
不会扰乱布局 - 子对象的布局与没有vptr
时完全相同。That map would have to store those
void*
pointers that are likely size ofvptr
, so there's actually more memory used, sincevptr
s will have to be stored just as well. And map lookup is not trivial - if there's a collision you have to perform linear search until the exact match is found. So lookups will be slower on average and more memory will be used.Actually prepending an object with
vptr
doesn't mess the layout - subobjects are laid out exactly as without avptr
.C++ 不一定有 v 表,尽管这是所有主要编译器都采取的路线。
除非你有虚方法,否则你不会得到虚函数表指针。如果您不需要,请不要使用虚拟。如果您只需要 POD,则使用 C。
这能解决什么问题?
memset
仍然无法正常工作 - 它通过绕过复制方法来破坏引用。它也不能解决动态调度问题,因为 memset 不会向映射注册类型。C++ doesn't have to have a v-table, although that is the route all major compilers have taken.
You don't get a vtable pointer unless you have virtual methods. If you don't want one then don't use virtual. If you only want POD then use C.
What does this solve?
memset
still wouldn't work correctly - it breaks references by getting around copy methods. It also doesn't solve dynamic dispatch, formemset
wouldn't register the type with the map.这里有一个严重的误解。
具有虚方法的类和非 POD 之间有一个非常显着的区别:复制构造函数的存在是有原因的。
简单例子(简化):
这个类从布局上来说就是一个POD。然而,memcpy 会公然违反使用条款并导致未定义的行为:复制构造函数被删除是有原因的!
然而,没有虚拟方法。
任何拥有内存的类,无论是直接还是间接,都是非POD。考虑到实际使用中嵌入
std::string
的类的数量...这是一个相当常见的场景。那 Go 呢?有一个垃圾收集器...
现在,这并不意味着应该使用虚拟方法(以及虚拟指针)构建类,但这样做肯定更简单。我个人是 Shims 的粉丝,但是那里出现了内存所有权/对象生命周期问题。
There is a gross misunderstanding here.
There is a very significant difference between a class with virtual methods and a non-POD: copy constructors exist for a reason.
Simple example (simplified):
This class is a POD in terms of layout. However a
memcpy
would be a blatant violation of the terms of use and lead to undefined behavior: the copy constructor is deleted for a reason!Yet, no virtual method.
Any class that owns memory, whether directly or indirectly, is a non-POD. Given the number of classes in real usage which embeds a
std::string
... it's a rather common scenario.What about Go then ? There is a Garbage Collector...
Now, it does not mean that classes should be built with virtual methods (and thus virtual pointers), but it certainly simpler to do so. I am personally a fan of Shims, however there are memory ownership/objects lifetime issues that spring up there.