为何使用shared_ptr的简单C++程序出现段错误?
问题描述
这段使用std::shared_ptr<char[]>的C++程序运行时出现段错误,但换成std::unique_ptr<char[]>就正常。是不是因为不该用std::make_shared<char[]>(BLOCKSIZE)初始化block?
代码如下:
#include <memory> #include <iostream> #define BLOCKSIZE 100000 struct MyClass { std::shared_ptr<char[]> block; MyClass() : block(std::make_shared<char[]>(BLOCKSIZE)) {} void fill_block() { for (size_t i = 0; i < BLOCKSIZE; ++i) { block[i] = static_cast<char>(i % 99); } } void print_one(size_t i) { if (i < BLOCKSIZE) { std::cout << static_cast<int>(block[i]); } else { std::cout << "Index out of range!"; } } }; int main() { for (size_t i = 0; i < 1000; ++i) { MyClass x; x.fill_block(); x.print_one(i); } return 0; }
运行命令及结果:
g++ shared_ptr_test.cpp -o shared_ptr_test ./shared_ptr_test Segmentation fault
原因分析
核心问题是C++版本兼容性:
std::unique_ptr<T[]>从C++11开始就原生支持数组类型,配套的数组操作(比如operator[])和正确的删除器(自动调用delete[])都是合规的。- 但
std::shared_ptr<T[]>以及数组版本的std::make_shared<T[]>是C17才引入的特性。如果你的编译器默认使用C17之前的标准(比如g默认用C14),那么std::shared_ptr<char[]>和std::make_shared<char[]>属于未定义行为:- 老版本的
shared_ptr不识别数组类型,会用默认的删除器(调用delete而非delete[])来释放内存,这会导致内存泄漏或堆损坏。 - 同时,
operator[]对于C++17之前的shared_ptr<T[]>也不是标准支持的操作,访问block[i]会触发非法内存访问,最终导致段错误。
- 老版本的
解决方法
有两种可行的修复方案:
升级编译标准到C++17及以上:
编译时添加-std=c++17参数,让编译器支持shared_ptr的数组特性:g++ shared_ptr_test.cpp -o shared_ptr_test -std=c++17这样
std::make_shared<char[]>和shared_ptr<char[]>::operator[]都会按标准工作,不会出现段错误。在C++17之前的标准下手动指定删除器:
如果无法升级C++版本,不要用make_shared<char[]>,而是手动创建数组并指定正确的删除器:MyClass() : block(new char[BLOCKSIZE], std::default_delete<char[]>()) {}这样
shared_ptr会用delete[]释放数组内存,同时operator[]虽然不是标准支持,但很多编译器(比如g++)会提供扩展支持,能正常访问数组元素。
内容的提问来源于stack exchange,提问作者thc
相关产品推荐
相关产品推荐

