C++ 向动态数组添加外部对象时静态计数器额外递增原因求解
问题根源
你的计数异常是两个核心问题共同导致的:
- X类仅在默认构造、析构中处理计数,缺失拷贝构造函数的计数逻辑,编译器自动生成的隐式拷贝构造/拷贝赋值运算符不会修改
xCounter - 你用
new X[N]创建动态数组时,会强制为每个数组元素调用默认构造函数(触发xCounter递增),后续的赋值操作不会抵消这次多余的构造计数,只是覆盖对象的内容。
第一次调用y += X()过程(巧合输出正常)
- 临时
X()对象创建,调用默认构造,xCounter = 1 - 进入
operator+=,此时yCounter = 0,执行new X[1],数组元素调用默认构造,xCounter = 2 - 将临时对象赋值给新数组的第0位,调用隐式拷贝赋值运算符,计数无变化
- 原
collection是空指针,delete[]无操作,collection指向新数组,yCounter变为1 - 函数退出后,临时
X()对象析构,xCounter = 2 - 1 = 1
此时输出的xCount=1刚好符合预期,属于巧合,逻辑本身已经存在问题。
第二次调用y += x过程(暴露异常)
- 执行
X x;创建外部对象,调用默认构造,xCounter = 1 + 1 = 2 - 进入
operator+=,此时yCounter = 1,执行new X[2],2个数组元素分别调用默认构造,xCounter = 2 + 2 = 4 - 循环将原数组的1个元素赋值给新数组前1位,再将外部
x赋值给新数组第1位,两次赋值都不修改计数 delete[]原数组,原数组的1个元素析构,xCounter = 4 - 1 = 3collection指向新数组,yCounter变为2,函数退出
此时输出的xCount=3就是你看到的异常结果,3个计数分别对应:新数组里的2个X对象、外部定义的X对象x。
修复方案
要彻底解决问题需要做两处修改:
- 给X类补充拷贝构造函数,确保所有创建X对象的场景都能正确计数:
class X { static int xCounter; public: X() { xCounter++; } // 补充拷贝构造逻辑 X(const X& other) { xCounter++; } ~X() { xCounter--; } static int XCount() { return xCounter; } };
- 修改Y类的动态数组实现逻辑,不要直接用
new X[]创建数组(避免多余的默认构造调用),改用未初始化内存+定位new手动调用拷贝构造来创建元素:
Y& operator+=(const X& item) { // 先申请足够的未初始化内存,不触发X的构造函数 X* tempCollection = static_cast<X*>(operator new[](sizeof(X) * (yCounter + 1))); // 拷贝构造原有元素 for (int i = 0; i < yCounter; i++) new (&tempCollection[i]) X(this->collection[i]); // 拷贝构造新加入的元素 new (&tempCollection[yCounter]) X(item); // 手动析构+释放原有数组 for (int i = 0; i < yCounter; i++) collection[i].~X(); operator delete[](collection); collection = tempCollection; yCounter++; return *this; }
修改后你可以加作用域测试,外部x析构后xCount就会和yCount完全一致,符合预期。
内容的提问来源于stack exchange,提问作者Cody
相关产品推荐
相关产品推荐

