使用std::fill填充默认构造std::string触发段错误的原因咨询
为什么allocator分配内存后用std::fill会触发段错误?
核心问题本质
std::allocator::allocate(n)只负责分配能容纳n个TESTED_TYPE的原始未初始化内存,完全不会在这块内存上构造任何对象。
而std::fill的逻辑是遍历区间内的每个元素,执行*it = value的赋值操作——这就踩了非POD类型的雷:
- 对于
int、char这类POD类型,赋值可以直接作用于原始内存(POD类型不需要构造就能合法赋值),所以运行正常。 - 对于
std::string这类非POD类型,*it = val调用的是std::string::operator=,这个成员函数默认会先清理当前对象持有的资源(比如释放内部存储字符串的堆内存)。但此时*it指向的是原始内存,里面的内容是随机垃圾值,相当于调用一个完全未初始化对象的成员函数,直接触发未定义行为(表现为段错误)。
为什么传入非空std::string时看似不崩溃?
这只是未定义行为的偶然表现,代码依然是错误的。
不同std::string实现的内部结构有差异:比如有些实现中,空string的内部指针是nullptr,而原始内存里的垃圾值可能是一个非法地址,赋值时触发非法释放导致崩溃;而非空string的赋值操作可能先覆盖了内部指针,没来得及触发非法内存访问。但这完全是依赖运行环境的巧合,不存在“合法”的逻辑。
正确的处理方式
必须先在分配的内存上构造对象,再进行赋值,推荐两种方式:
方式1:用allocator的construct方法逐个构造
#define TESTED_TYPE std::string size_t n = 5; std::allocator<TESTED_TYPE> my_alloc; TESTED_TYPE *data = my_alloc.allocate(n); TESTED_TYPE val = TESTED_TYPE(); for (size_t i = 0; i < n; ++i) { my_alloc.construct(data + i, val); // 先构造对象,再完成复制 }
方式2:用std::uninitialized_fill直接构造并填充
这个工具函数专门针对原始内存,会自动完成对象构造和填充:
#define TESTED_TYPE std::string size_t n = 5; std::allocator<TESTED_TYPE> my_alloc; TESTED_TYPE *data = my_alloc.allocate(n); TESTED_TYPE val = TESTED_TYPE(); std::uninitialized_fill(data, data + n, val);
内容的提问来源于stack exchange,提问作者bperraud
相关产品推荐
相关产品推荐

