实现动态数组拷贝构造函数时触发delete_scalar.cpp错误求助
解决DynamicArray类的delete_scalar.cpp内存错误问题
问题根源
未实现拷贝赋值运算符
你只定义了拷贝构造函数,但未重载operator=,编译器会生成默认的拷贝赋值运算符,它执行浅拷贝:直接将obj的arr指针值复制给obj2,导致两个对象的arr指向同一块堆内存。程序结束时,两个对象的析构函数会先后调用delete[]释放同一块内存,触发重复释放的内存错误,这就是Visual Studio弹出delete_scalar.cpp错误的核心原因。成员函数设计冗余且易出错
add和print作为类的成员函数,完全不需要传入对象指针,直接访问当前对象的arr、number_of_elements等成员变量即可,当前写法不仅冗余,还容易引发指针误用。拷贝构造函数的内存分配偏差
拷贝构造函数中分配内存时使用other.number_of_elements,但实际应使用other.capacity——数组的容量由capacity定义,如果后续给拷贝出的对象添加元素,会因内存容量不足导致越界。
修复方案
1. 实现拷贝赋值运算符(遵循三法则)
当类包含堆内存指针时,必须自定义拷贝构造函数、拷贝赋值运算符、析构函数(三法则)。实现拷贝赋值时需注意:
- 先检查自赋值,避免自身赋值导致的内存错误
- 释放当前对象已占用的内存
- 分配新内存并拷贝数据
- 返回当前对象的引用
2. 修正add和print函数
移除不必要的对象指针参数,直接操作当前对象的成员变量。
3. 修正拷贝构造函数的内存分配
将arr(new int[other.number_of_elements])改为arr(new int[other.capacity]),保证拷贝后的对象容量与原对象一致。
修正后的完整代码
DynamicArray.h
#pragma once class DynamicArray { private: int* arr; int capacity; int number_of_elements; public: DynamicArray(int capacity = 1); DynamicArray(const DynamicArray&); // 添加拷贝赋值运算符声明 DynamicArray& operator=(const DynamicArray&); ~DynamicArray(); // 修正函数参数 void add(int value); void print(); };
DynamicArray.cpp
#include "DynamicArray.h" #include <iostream> DynamicArray::DynamicArray(int capacity) : capacity(capacity), number_of_elements(0), arr(new int[capacity]) {} DynamicArray::~DynamicArray() { delete[] this->arr; this->arr = nullptr; this->number_of_elements = 0; this->capacity = 0; } // 修正拷贝构造函数的内存分配逻辑 DynamicArray::DynamicArray(const DynamicArray& other) : capacity(other.capacity), number_of_elements(other.number_of_elements), arr(new int[other.capacity]) { for (int i = 0; i < number_of_elements; i++) { this->arr[i] = other.arr[i]; } } // 实现拷贝赋值运算符 DynamicArray& DynamicArray::operator=(const DynamicArray& other) { // 检查自赋值 if (this == &other) return *this; // 释放当前对象的内存 delete[] this->arr; // 分配新内存并拷贝数据 this->capacity = other.capacity; this->number_of_elements = other.number_of_elements; this->arr = new int[this->capacity]; for (int i = 0; i < this->number_of_elements; i++) { this->arr[i] = other.arr[i]; } return *this; } // 修正add函数:直接操作当前对象,补充扩容逻辑 void DynamicArray::add(int value) { // 处理容量不足的情况,简单扩容为原容量的2倍 if (number_of_elements >= capacity) { int* new_arr = new int[capacity * 2]; for (int i = 0; i < number_of_elements; i++) { new_arr[i] = arr[i]; } delete[] arr; arr = new_arr; capacity *= 2; } arr[number_of_elements++] = value; } // 修正print函数:直接操作当前对象 void DynamicArray::print() { for (int i = 0; i < number_of_elements; i++) { std::cout << arr[i] << " "; } std::cout << std::endl; }
main.cpp
#include "DynamicArray.h" int main() { DynamicArray obj(5); DynamicArray obj2(5); obj.add(22); obj.add(12); obj.add(18); obj.add(11); obj.print(); obj2 = obj; obj2.print(); }
额外说明
- 三法则:当类管理堆内存资源时,必须自定义拷贝构造函数、拷贝赋值运算符、析构函数,避免浅拷贝引发的内存泄漏或重复释放问题。
- 扩容逻辑:原代码未处理容量不足的情况,添加元素超过初始容量时会触发越界错误,修正后的代码补充了基础的扩容逻辑。
内容的提问来源于stack exchange,提问作者Wikallou
相关产品推荐
相关产品推荐

