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

代码报错‘pointer being freed was not allocated’的原因及修复方法

自定义C++ Vector类的内存错误修复

错误日志

12 SIZE: 3 CAPACITY: 4
12 SIZE: 4 CAPACITY: 4
DESTRUCTOR
proj1(53055,0x10121c580) malloc: *** error for object 0x600001ac1110: pointer being freed was not allocated
proj1(53055,0x10121c580) malloc: *** set a breakpoint in malloc_error_break to debug
zsh: abort      /Users/mascai/root_folder/dev/projects/03_cpp_examples/02_ide/build/proj1

问题代码

template<class T>
class Vector {
public:
    Vector() = default;
    Vector(size_t size) : size_(size), capacity_(size * 2) {
        data_= new T[capacity_];
    }
    Vector(size_t size, const T val) : size_(size), capacity_(size * 2) {
        data_= new T[capacity_];
        for (size_t i = 0; i < size_; ++i) {
            data_[i] = val;
        }
    }
    Vector(const Vector& other) {
        data_ = other.data_;
        size_ = other.size_;
        capacity_ = other.capacity_;
    }
    const Vector& operator=(const Vector<T>& other) {
        data_ = other.data_;
        size_ = other.size_;
        capacity_ = other.capacity_;
        return *this;
    }
    ~Vector() {
        cout << "DESTRUCTOR" << endl;
        if (data_) {
            delete[] data_;
        }
        size_ = 0;
        capacity_ = 0;
    }

    T operator[](size_t idx) const {
        if (idx < size_) {
            return *(data_ + idx);
        }
        throw std::invalid_argument("Inde out of range");
    }

    void push_back(const T& val) {
        size_ += 1;
        if (size_ > capacity_) {
            capacity_ *= 2;
            T* new_data = new T[capacity_];
            for (int i = 0; i < size_ - 1; ++i) {
                *new_data++ = *data_++;
            }
            delete[] data_;
            data_ = new_data;
        } else {
            *(data_ + size_ - 1) = val;
        }
    }

    size_t size() const {
        return size_;
    }

    size_t capacity() const {
        return capacity_;
    }

private:
    T* data_ = nullptr;
    size_t size_ = 0;
    size_t capacity_ = 0;
};


int main() {
    Vector<int> v(2, 111);
    assert(v[0] == 111);
    v.push_back(12);
    cout << v[2] << " SIZE: " << v.size() << " CAPACITY: " << v.capacity() << endl;
    v.push_back(12);
    cout << v[3] << " SIZE: " << v.size() << " CAPACITY: " << v.capacity() << endl;
    v.push_back(13);
}

错误原因分析

  1. push_back指针非法偏移:扩容拷贝元素时,*new_data++ = *data_++会修改data_的指向,使其从数组首地址移到末尾。后续delete[] data_释放的不是最初分配的首地址,触发内存释放错误。
  2. 浅拷贝的双重释放隐患:拷贝构造和赋值运算符直接复制指针,多个Vector对象共享同一块内存,析构时会重复释放已释放的内存。
  3. size递增时机不合理:先递增size_再判断扩容,拷贝元素时需用size_-1获取原元素数量,增加出错概率。

修复步骤

1. 修复push_back的指针偏移问题

拷贝元素时不移动原始data_指针,改用索引访问,同时调整size递增时机:

void push_back(const T& val) {
    if (size_ >= capacity_) {
        // 空容器第一次扩容时初始化容量为1
        capacity_ = capacity_ == 0 ? 1 : capacity_ * 2;
        T* new_data = new T[capacity_];
        for (size_t i = 0; i < size_; ++i) {
            new_data[i] = data_[i];
        }
        delete[] data_;
        data_ = new_data;
    }
    data_[size_] = val;
    size_++;
}

2. 实现深拷贝的拷贝构造函数

Vector(const Vector& other) : size_(other.size_), capacity_(other.capacity_) {
    data_ = new T[capacity_];
    for (size_t i = 0; i < size_; ++i) {
        data_[i] = other.data_[i];
    }
}

3. 用拷贝交换惯用法实现赋值运算符

这种写法更简洁安全,自动处理内存管理:

Vector& operator=(Vector other) {
    std::swap(data_, other.data_);
    std::swap(size_, other.size_);
    std::swap(capacity_, other.capacity_);
    return *this;
}

4. 修复operator[]的细节

添加非const版本支持修改元素,同时修正拼写错误:

// 非const版本,支持修改元素
T& operator[](size_t idx) {
    if (idx < size_) {
        return data_[idx];
    }
    throw std::invalid_argument("Index out of range");
}

// const版本,只读访问
const T& operator[](size_t idx) const {
    if (idx < size_) {
        return data_[idx];
    }
    throw std::invalid_argument("Index out of range");
}

修复后的完整代码

#include <iostream>
#include <cassert>
#include <algorithm>

template<class T>
class Vector {
public:
    Vector() = default;
    Vector(size_t size) : size_(size), capacity_(size * 2) {
        data_ = new T[capacity_];
    }
    Vector(size_t size, const T val) : size_(size), capacity_(size * 2) {
        data_ = new T[capacity_];
        for (size_t i = 0; i < size_; ++i) {
            data_[i] = val;
        }
    }
    Vector(const Vector& other) : size_(other.size_), capacity_(other.capacity_) {
        data_ = new T[capacity_];
        for (size_t i = 0; i < size_; ++i) {
            data_[i] = other.data_[i];
        }
    }
    Vector& operator=(Vector other) {
        std::swap(data_, other.data_);
        std::swap(size_, other.size_);
        std::swap(capacity_, other.capacity_);
        return *this;
    }
    ~Vector() {
        std::cout << "DESTRUCTOR" << std::endl;
        delete[] data_; // nullptr时delete[]安全,无需判断
        size_ = 0;
        capacity_ = 0;
    }

    T& operator[](size_t idx) {
        if (idx < size_) {
            return data_[idx];
        }
        throw std::invalid_argument("Index out of range");
    }

    const T& operator[](size_t idx) const {
        if (idx < size_) {
            return data_[idx];
        }
        throw std::invalid_argument("Index out of range");
    }

    void push_back(const T& val) {
        if (size_ >= capacity_) {
            capacity_ = capacity_ == 0 ? 1 : capacity_ * 2;
            T* new_data = new T[capacity_];
            for (size_t i = 0; i < size_; ++i) {
                new_data[i] = data_[i];
            }
            delete[] data_;
            data_ = new_data;
        }
        data_[size_] = val;
        size_++;
    }

    size_t size() const {
        return size_;
    }

    size_t capacity() const {
        return capacity_;
    }

private:
    T* data_ = nullptr;
    size_t size_ = 0;
    size_t capacity_ = 0;
};


int main() {
    Vector<int> v(2, 111);
    assert(v[0] == 111);
    v.push_back(12);
    std::cout << v[2] << " SIZE: " << v.size() << " CAPACITY: " << v.capacity() << std::endl;
    v.push_back(12);
    std::cout << v[3] << " SIZE: " << v.size() << " CAPACITY: " << v.capacity() << std::endl;
    v.push_back(13);
    std::cout << v[4] << " SIZE: " << v.size() << " CAPACITY: " << v.capacity() << std::endl;
}

内容的提问来源于stack exchange,提问作者mascai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:10:57