You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 07:25:20