HasPtr类排序后对象计数器均为3的原因分析及修复方案
问题分析:计数器值为3的原因
1. swap函数破坏了引用计数的对应关系
原swap函数仅交换了ps和i,但未交换use指针。这直接违反了"共享同一字符串的对象必须共享同一计数器"的设计逻辑:
- 交换后,对象持有的字符串指针
ps与引用计数器use不再匹配,比如交换lhs和rhs后,lhs拿着rhs原来的字符串,却仍用自己的计数器统计引用数。 std::sort排序过程中会频繁执行交换、赋值操作,错误的swap会让引用计数的增减完全混乱,导致计数器值偏离实际引用数量。
2. 遍历过程的额外拷贝放大计数
主函数的范围for循环使用auto letter : vec是值拷贝遍历,vector中的每个元素都会被拷贝构造一次,每个元素的引用计数器因此额外+1。结合swap导致的计数混乱,最终所有对象的计数器值变为3。
3. 初始拷贝的基础计数
vector初始化vec{d,a,c,e,b}时,所有元素都是通过拷贝构造创建的,此时原对象(a-e)和vector中的对应元素共享计数器,每个计数器的初始值为2。
修复方案
1. 修正swap函数,添加use指针的交换
swap必须保证交换后,每个对象的ps和use仍保持正确的对应关系:
inline void swap(HasPtr& lhs, HasPtr& rhs) { using std::swap; swap(lhs.ps, rhs.ps); swap(lhs.i, rhs.i); swap(lhs.use, rhs.use); // 新增:交换use指针,维持ps与use的对应 }
2. 补充缺失的get_use()成员函数
主函数中调用了letter.get_use(),原类未提供该函数,需在HasPtr的public区域添加:
std::size_t get_use() const { return *use; }
3. 优化遍历方式(可选但推荐)
将范围for循环改为引用遍历,避免不必要的拷贝构造,减少计数器的无意义增长:
for (const auto& letter : vec) // 使用const引用遍历 { std::cout << *letter.ps << " " << letter.get_use() << std::endl; }
修复后的预期结果
修正后,若使用引用遍历,排序完成后每个vector元素的计数器值应为1(原对象a-e在vector初始化后无其他引用,析构时会将计数器减至1,vector元素持有唯一引用);若仍保留值拷贝遍历,计数器值会是2(vector元素+遍历产生的临时对象)。
内容的提问来源于stack exchange,提问作者iamnotevg
相关产品推荐
相关产品推荐

