c++编译器中的pod和VPtr设计
PODs and VPtr Design in C++ Compilers
这个问题更多的是关于语言设计,而不是关于改变c++的约定。
在考虑Go编程语言(它如何将数据从接口中分离出来,有效地将所有对象转换为结构体)和c++中的pod(我喜欢在分配大量小型结构体类对象时使用memset/memcpy)时,我想知道 c++编译器将vptr直接附加到对象的实例的惯例,这会弄乱布局。
这是一个要求还是一个惯例?
如果你正在设计一个替代编译器,你能有一个大的外部查找表来代替vptr吗?例如, map<void*,vptr>
?就内存设置而言,所有实例都是POD,要查找它的vptr,我们将获取它的地址并查看大型外部查找表。
缺点是,所有内容都需要查找。这是一个可行的替代设计还是有严重的缺点?
性能很可能会受到影响。有些语言为方法查找添加了某种缓存。
对于给定的选择器(或方法名),您可以使用不同的方法来查找要调用的方法。看看Smalltalk, Self, Javascript, Common Lisp Object system或者Ocaml
然而,一些语言的实现包含巧妙的技巧(缓存,JIT,…),使它们与c++一样快(但这是实现问题,而不是语言设计问题)。
该映射必须存储那些void*
指针,这些指针可能与vptr
大小相同,因此实际上使用了更多的内存,因为vptr
s也必须存储。map查找不是简单的——如果有碰撞,你必须执行线性搜索,直到找到完全匹配。因此,查找平均速度会变慢,并且会使用更多的内存。
实际上,在对象前加上vptr
并不会打乱布局——子对象的布局与没有vptr
时完全一样。
c++并不一定要有v-table,尽管这是所有主流编译器都采用的路线。
除非有虚方法,否则不会得到虚表指针。如果你不想要,那就不要使用virtual。如果只需要POD,则使用c。
如果你正在设计一个可替代的编译器,你能有一个大的外部查找表来代替vptr吗?例如,像map?就内存设置而言,所有实例都是POD,要查找它的vptr,我们将获取它的地址并查看大型外部查找表。
这解决了什么?memset
仍然不能正常工作-它通过绕过复制方法来破坏引用。它也不能解决动态调度问题,因为memset
不会将类型注册到映射中。
所有实例都是POD
这里有一个严重的误解。
具有虚方法的类和非pod的类之间有一个非常重要的区别:复制构造函数的存在是有原因的。
简单示例(简化):
template <typename T>
class unique_ptr {
public:
unique_ptr(): _ptr(nullptr) {}
explicit unique_ptr(T* p): _ptr(p) {}
unique_ptr(unique_ptr const&) = delete;
unique_ptr(unique_ptr&& other): _ptr(other._ptr) { other._ptr = 0; }
unique_ptr& operator=(unique_ptr other) {
std::swap(_ptr, other._ptr);
return *this;
}
~unique_ptr() { delete _ptr; }
T& operator*() const { return *_ptr; }
T* operator->() const { return _ptr; }
private:
T* _ptr;
}; // class unique_ptr<T>
这个类在布局上是一个POD。然而,memcpy
将公然违反使用条款并导致未定义的行为:复制构造函数被删除是有原因的!
然而,没有虚拟方法。
任何直接或间接拥有内存的类都是非pod。考虑到实际使用中嵌入std::string
的类的数量……这是一个相当常见的场景。
Go呢?
现在,这并不意味着类应该用虚方法(以及虚指针)来构建,但是这样做肯定更简单。我个人是Shims的粉丝,但是存在内存所有权/对象生命周期问题。
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 将寄存器设计成可由C和C++访问的外设的最佳实践
- 询问在设计我的手臂模拟器功能表示格式1
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 资源管理设计模式
- 多态杆件变量 - 类设计
- 如何设计具有不同类型的通知和观察器的观察者模式?
- 如何使用要传递给 mt19937 的可选随机种子参数设计函数
- 设计将引用元素移动到开头的数据结构.C++
- С++ wxWidgets:代码架构,设计原则和模式
- 用于在回调中调用解析器的设计模式
- 在设计 SDK 时,我是否应该在 C++ 头文件中完全隐藏内部类?
- 何时为派生类初始化 vptr?
- 需要为 C++ 中的以下问题设计递归算法
- 使用 SFINAE 设计模板方法
- C++,您能否设计一种数据结构,将指针保存在连续内存中并且不会使它们失效?
- 设计帮助 - 为不同类型的消息处理通用接口的设计模式
- C++模板编程设计问题 - 根据输入文件返回不同的类型
- c++编译器中的pod和VPtr设计