使用std::shared_ptr管理动态数组的技术问题求助
嘿,我太懂你从普通指针转智能指针时遇到的这些糟心事了!当初我刚上手shared_ptr管理数组的时候,也踩过一模一样的雷,咱们一个个拆解问题,再给你靠谱的解决方案:
先说说你遇到的三个问题的根源
1. std::shared_ptr<Entity> f1(new Entity[100])编译报错
你用的是非数组特化版的shared_ptr,它本身没有重载[]运算符,所以你想直接用f1[i].print()肯定编译不过。而且更隐蔽的问题是:这个shared_ptr默认的删除器是delete,不是delete[],就算你强行用f1.get()[i].print()能编译,最后销毁的时候也会因为用错删除器导致内存泄漏或者未定义行为。
2. std::make_shared<int>(100)访问f1.get()[1]触发内存错误
这里完全是理解错了make_shared的用法!std::make_shared<int>(100)是创建单个int对象,值为100,不是创建一个包含100个int的数组。你用get()[1]相当于访问单个int对象后面的内存,直接越界,不出错才怪。
3. std::shared_ptr<Entity[]> f1 = std::make_shared<Entity[]>(new Entity[100])报错
make_shared<Entity[]>的参数是数组的元素个数,不是你手动new出来的指针!它的作用就是帮你自动分配数组内存,不需要你自己写new,你传new Entity[100]完全是画蛇添足,类型不匹配自然报错。
正确实现动态数组管理的方式(C++17+推荐)
从C++17开始,标准库提供了std::shared_ptr<T[]>的数组特化版本,完美适配动态数组场景:它支持[]运算符,默认删除器是delete[],用法和普通指针的动态数组几乎一致。
管理自定义类型(比如Entity)的数组
// 方式1:用make_shared创建(推荐,更安全,避免内存泄漏) std::shared_ptr<Entity[]> f1 = std::make_shared<Entity[]>(100); // 这里的100是数组元素个数,make_shared会自动分配并初始化100个Entity对象 f1[0].print(); // 直接用[]访问元素,和普通指针一样 f1[99].print(); // 访问最后一个元素也没问题 // 方式2:直接用new初始化(不推荐,不如make_shared安全) std::shared_ptr<Entity[]> f1(new Entity[100]); f1[5].print(); // 同样可以正常调用成员方法
管理内置类型(比如int)的数组
// 创建包含100个int的数组,默认值是0 std::shared_ptr<int[]> f1 = std::make_shared<int[]>(100); f1[1] = 42; // 给第二个元素赋值 std::cout << f1[1] << std::endl; // 正常输出42,不会触发内存错误
如果你还在使用C++17之前的版本
那只能手动指定删除器来处理数组,写法会麻烦一点,但也能实现需求:
// 自定义删除器,用delete[]销毁数组 std::shared_ptr<Entity> f1(new Entity[100], [](Entity* ptr) { delete[] ptr; }); // 访问元素时需要先调用get()拿到原始指针,再用[] f1.get()[0].print();
不过还是建议尽量升级到C++17及以后的版本,数组特化版的shared_ptr用起来舒服太多了。
内容的提问来源于stack exchange,提问作者Claudiu Andries

