为什么std::vector允许使用不完整类型?编译器是如何处理该场景的?
编译器不报错的核心原因可以从标准规则和vector的实现逻辑两部分解释:
- 标准规则演进:C17之前的标准要求,实例化标准库容器时元素必须是完整类型(即已经完成全部定义、内存布局和大小可确定),否则属于未定义行为。但C17开始,标准明确放开了限制:
std::vector、std::list、std::forward_list三个容器允许在实例化时使用不完整类型,只要在执行需要用到元素大小/布局的操作之前,类型完成定义即可。就算你用C11/14标准编译,gcc自带的libstdc也提前做了非标准扩展支持这种用法,所以不会触发报错。 - 代码执行时序符合要求:你这段代码里,在Node结构体内部声明
std::vector<Node> children时,Node确实还没遇到闭合的},属于不完整类型,但这一步只是实例化vector的模板定义,不需要知道Node的大小:vector本身的内存布局只需要存三个指针(动态数组首地址、当前使用尾地址、容量尾地址),不管元素类型是什么,vector本身的大小都是固定的三个指针的大小,所以这一步完全可以正常编译。 - 等到Node结构体的闭合
}执行完,Node就变成了完整类型,后续你定义Node对象、调用push_back插入元素时,所有需要计算Node大小、调用拷贝构造函数的操作都能正常执行,完全符合规则要求。
你可以做个反向验证:如果换用必须在实例化时就知道元素大小的容器,比如std::array,写如下代码就会直接触发不完整类型的报错:
#include <array> struct Node { std::array<Node, 3> children; // array实例化必须提前知道元素大小,直接报错 };
内容的提问来源于stack exchange,提问作者Talespin_Kit
相关产品推荐
相关产品推荐

