C++中std::size()在一个程序正常运行,另一程序编译报错原因排查
问题原因分析
std::size对原生数组的工作前提
std::size获取原生数组长度的前提是,数组的长度在编译期可确定,编译器能推导得到数组类型对应的长度模板参数。第一个可正常运行的代码中,int array[]{ 30, 50, 20, 10, 40}会被编译器推导为int[5]类型,长度固定且编译期已知,所以可以匹配到std::size的数组重载,运行正常。
编译失败的核心原因
失败代码中定义的int components[]{}使用空初始化列表,会被GCC推导为int[0]类型(零长度数组):
- 零长度数组本身不是C++标准规定的合法语法,属于GCC的非标准扩展;
- std::size的原生数组重载
template<class _Tp, long unsigned int _Nm> constexpr std::size_t std::size(const _Tp (&)[_Nm])无法匹配零长度数组,模板参数_Nm推导失败,因此编译时报找不到匹配的size函数的错误。
报错信息中的两个候选重载:第一个是给带size()成员方法的标准容器用的,原生数组没有对应成员所以匹配失败;第二个就是上述的原生数组重载,零长度数组无法匹配所以最终编译失败。
隐藏的运行时风险
即使绕开编译错误,该代码也会触发未定义行为:零长度数组没有预留任何存储空间,在splitInteger函数中往components数组写入元素属于堆/栈内存越界访问,大概率会直接导致程序崩溃。
额外注意:原生数组作为函数参数传递时会自动退化为指针,就算你在splitInteger函数内调用std::size(components)也会失败,此时components的类型是int*,已经丢失了数组长度信息。
修复方案
- 明确拆分整数的最大长度提前分配数组空间:32位int类型的十进制最大长度为10位,直接定义固定长度数组
int components[10]{};,此时编译期已知长度为10,std::size可以正常调用。 - 修改
splitInteger函数返回拆分得到的有效元素个数,不用依赖数组长度拿实际拆分结果:
int splitInteger(int integer, int components[]) { int count{0}; do { int element{ integer % 10 }; components[count] = element; integer = integer / 10; ++count; } while(integer != 0); return count; }
在main中接收返回值即可获取实际拆分的位数:
int count = splitInteger(num, components); std::cout << count << '\n';
- 更安全的现代C++实现:使用
std::vector<int>代替原生数组,无需手动管理长度,天然支持std::size调用,也不存在数组退化为指针丢失长度的问题。
内容的提问来源于stack exchange,提问作者404 Not Found
相关产品推荐
相关产品推荐

