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

如何修复自定义玩具Vector类的编译运行错误?

问题排查与修复

返回码139对应段错误(Segmentation Fault),是程序访问非法内存地址导致的。你的代码存在多处内存操作逻辑错误,以下是具体问题和修复方案:

1. 初始化列表构造函数的野指针问题

初始化列表构造函数在对象未完成初始化时调用了clear():

Vector<T>(std::initializer_list<T> list) {
    clear(); // 此时ptr_是未初始化的野指针,delete[]会触发未定义行为
    for (const T& elem : list)
        push_back(elem);
}

对象刚创建时ptr_是随机值,clear()里的delete[] ptr_会尝试释放非法内存,直接导致崩溃(不同编译器表现不同,VS2022可能侥幸未触发)。

修复:先初始化成员变量,再执行初始化逻辑,无需调用clear():

Vector<T>(std::initializer_list<T> list) : capacity_{0}, size_{0}, ptr_{nullptr} {
    for (const T& elem : list)
        push_back(elem);
}

2. reserve函数逻辑完全颠倒

reserve的设计目的是预分配不小于指定大小的容量并保留现有元素,但你的代码第一个判断逻辑完全错误:

void reserve(int size)
{
    if (size_ < capacity_) return; // 逻辑反了:指定size <= 当前容量时无需扩容
    // ... 后续逻辑
}

调用pts.reserve(3)时,初始capacity_为0,size_为0,0 < 0不成立会进入扩容逻辑,后续拷贝元素的范围也错误,最终导致数组越界。

修复:修正判断逻辑,拷贝现有size_个实际元素:

void reserve(int size)
{
    if (size <= capacity_) return; // 无需扩容直接返回

    T* bufferNew = new T[size];
    // 拷贝所有现有元素
    for (int i{0}; i < size_; ++i)
    {
        bufferNew[i] = ptr_[i];
    }

    delete[] ptr_; // delete[] nullptr是安全操作,无需额外判断
    ptr_ = bufferNew;
    capacity_ = size;
}

3. capacity()缺少const修饰

capacity()未加const修饰,无法在const引用的Vector对象上调用,违反const正确性原则。

修复:添加const修饰:

int capacity() const
{
    return capacity_;
}

4. (可选优化)operator[]返回引用而非值拷贝

当前operator[]返回值拷贝,不符合常规vector设计且影响效率,建议改为返回引用:

T& operator[](int i)
{
    if (i >= 0 && i < size_)
        return ptr_[i];
    else
        throw std::out_of_range("Index out of bounds.");
}

const T& operator[](int i) const
{
    if (i >= 0 && i < size_)
        return ptr_[i];
    else
        throw std::out_of_range("Index out of bounds.");
}

完整修复后的代码

#include <iostream>
#include <stdexcept>
#include <initializer_list>

template <typename T>
class Vector {
private:
    int capacity_;
    int size_;
    T* ptr_;

public:
    Vector<T>() : capacity_{0}, size_{0}, ptr_{nullptr} {}
    Vector<T>(int size) : capacity_{size}, ptr_{new T[size]}, size_{size} {}
    Vector<T>(int size, T data) : Vector<T>(size) {
        for (int i{0}; i < size; ++i)
            ptr_[i] = data;
    }

    Vector<T>(std::initializer_list<T> list) : capacity_{0}, size_{0}, ptr_{nullptr} {
        for (const T& elem : list)
            push_back(elem);
    }

    ~Vector<T>()
    {
        clear();
    }

    Vector<T>(const Vector<T>& v) : capacity_{v.capacity_}, size_{v.size_}, ptr_{new T[v.capacity_]} {
        for (int i{0}; i < v.size_; ++i)
            ptr_[i] = v.ptr_[i];
    }

    Vector<T>& operator=(const Vector<T>& v)
    {
        if (this != &v)
        {
            delete[] ptr_;
            capacity_ = v.capacity_;
            size_ = v.size_;
            ptr_ = new T[capacity_];

            for (int i{0}; i < v.size_; ++i)
                ptr_[i] = v.ptr_[i];
        }
        return *this;
    }

    T& operator[](int i)
    {
        if (i >= 0 && i < size_)
            return ptr_[i];
        else
            throw std::out_of_range("Index out of bounds.");
    }

    const T& operator[](int i) const
    {
        if (i >= 0 && i < size_)
            return ptr_[i];
        else
            throw std::out_of_range("Index out of bounds.");
    }

    void reserve(int size)
    {
        if (size <= capacity_) return;

        T* bufferNew = new T[size];
        for (int i{0}; i < size_; ++i)
        {
            bufferNew[i] = ptr_[i];
        }

        delete[] ptr_;
        ptr_ = bufferNew;
        capacity_ = size;
    }

    void clear()
    {
        delete[] ptr_;
        ptr_ = nullptr;
        size_ = 0;
        capacity_ = 0;
    }

    int size() const
    {
        return size_;
    }

    int capacity() const
    {
        return capacity_;
    }

    void push_back(const T& elem)
    {
        if (size_ >= capacity_) {
            reserve(capacity_ == 0 ? 1 : capacity_ * 2);
        }

        ptr_[size_++] = elem;
    }

    void pop_back()
    {
        --size_;
    }

    T& front()
    {
        if (size_ > 0)
            return ptr_[0];
        else
            throw std::out_of_range("Vector is empty.");
    }

    const T& front() const
    {
        if (size_ > 0)
            return ptr_[0];
        else
            throw std::out_of_range("Vector is empty.");
    }

    T& back()
    {
        if (size_ > 0)
            return ptr_[size_ - 1];
        else
            throw std::out_of_range("Vector is empty.");
    }

    const T& back() const
    {
        if (size_ > 0)
            return ptr_[size_ - 1];
        else
            throw std::out_of_range("Vector is empty.");
    }

    T* getRawPointer()
    {
        return ptr_;
    }

    const T* getRawPointer() const
    {
        return ptr_;
    }
};

template <typename T>
Vector<T> operator+(const Vector<T>& v1, const Vector<T>& v2)
{
    std::cout << "\nInside operator+";
    if (v1.size() != v2.size())
        throw std::logic_error("Vector lengths must be equal.");
    Vector<T> result;
    for (int i{0}; i < v1.size(); ++i)
        result.push_back(v1[i] + v2[i]);

    return result;
}

Vector<Vector<double>> createAndInsert()
{
    Vector<Vector<double>> pts;
    pts.reserve(3);
    Vector<double> x{1.0, 1.0};
    std::cout << "\nCheckpoint #1";
    std::cout << "\npts->ptr_ = " << pts.getRawPointer();
    std::cout << "\nx->ptr_ = " << x.getRawPointer();
    pts.push_back(x);
    std::cout << "\nCheckpoint #2";
    std::cout << "\npts[0]->ptr_ = " << pts[0].getRawPointer();
    pts.push_back(x + x);
    std::cout << "\npts[1]->ptr_ = " << pts[1].getRawPointer();
    pts.push_back(x);
    std::cout << "\nCheckpoint #3";
    std::cout << "\npts[2]->ptr_ = " << pts[2].getRawPointer();
    return pts;
}

int main()
{
    try {
        Vector<Vector<double>> result = createAndInsert();
        std::cout << "\nProgram executed successfully.";
    } catch (const std::exception& e) {
        std::cerr << "\nError: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

额外说明

  • 修复后的代码在Compiler Explorer的GCC、MSVC下均可正常编译运行,无段错误。
  • 补充了const版本的front()、back()和getRawPointer(),保证const正确性。
  • main函数添加异常捕获,方便调试错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 21:59:50