尝试打印某些值时未处理的异常

Unhandled exception while trying to print some value

提问人:Satoshic 提问时间:8/24/2023 最后编辑:Remy LebeauSatoshic 更新时间:8/24/2023 访问量:71

问:

我正在编写自己的实现,当我尝试打印一个数字时,有时我在尝试打印它的行上遇到异常。我知道问题出在内存中,但我不知道为什么当我使用我的函数初始化内存时内存保持未初始化状态。vector

#include <iostream>
#include <memory>
#include <algorithm>
using namespace std;

template <typename T>
class badvector {
private:
    uint64_t _size;
    uint64_t _capacity;
    shared_ptr<T[]> arrptr;
    bool resizable;
    void initialize() {
        for (int i = 0; i < _size; i++) {
            arrptr[i] = 0;
        }
    }
    void initialize(uint64_t sz, shared_ptr<T[]> &ptrarr) {
        for (int i = 0; i < _size; i++) {
            ptrarr[i] = 0;
        }
    }
    void capacity_count() {
        _capacity = 0;
        for (int i = 0; i < _size; i++) {
            if (arrptr[i] != 0) {
                ++_capacity;
            }
        }
        if (_capacity > _size) {
            throw "error, capacity out of range";
        }
    }
public:
    explicit badvector() : _size(5), _capacity(0), arrptr(new T[5]), resizable(true) {
        initialize();
    }
    ~badvector() = default;
    uint64_t get_cp() {
        capacity_count(); 
        return this->_capacity;
    }
    uint64_t size() {
        return this->_size;
    }
    void push_back(T arg) {
        capacity_count();
        if (_capacity == _size) {
            resize(_size + 5);
        }
        arrptr[_capacity] = arg;
        ++this->_capacity; 
        capacity_count();
    }
    void reserve(uint64_t sz) {
        _size = sz;
        if (!resizable) {
            throw "Error, you are not able to reserve any more place, you used resize";
        }
        capacity_count();
        shared_ptr<T[]> temp(new T[sz]);
        initialize(sz, temp);
        for (int i = 0; i < _capacity; i++) {
            temp[i] = arrptr[i];
        }
        arrptr = temp;
        capacity_count();
    }
    void resize(uint64_t sz) {
        reserve(sz);
        resizable = false;
    }
    T operator[](uint64_t position) {
        capacity_count();
        if (position >= _capacity || position < 0) {
            throw "badvector out of range";
        };
        return *(arrptr.get() + position);
    }
    void print(uint64_t num) {
        capacity_count();
        if (num >= _capacity || num < 0) {
            throw "badvector out of range";
        }
        cout << arrptr[num] << endl;
    }
    const T* cbegin() const {
        return arrptr.get();
    }
    T* begin(){
        return arrptr.get();
    }
    const T* cend() const {
        return arrptr.get() + _size;
    }
    T* end() {
        return arrptr.get() + _size;
    }
};

int main() {
    badvector<int> b;
    b.reserve(30);
    cout << "size " << b.size() << endl << "capacity " << b.get_cp() << endl;
    for (int i = 0; i < 30; i++) {
        b.push_back(42);
    }
    cout << "size after push_back: " << b.size() << endl << "capacity after push_back: " << b.get_cp() << endl;
    for (auto i = b.begin(); i != b.end(); i++) {
        cout << b[*i] << endl;
    }
}

我真的不知道为什么会这样。可能其中一个变体是使用 nullptr 初始化数组?

C++ 数组 异常 内存 输出

评论

1赞 user4581301 8/24/2023
方便的工具编译器选项:如果支持,它会准确地告诉您发生了什么以及运行程序的位置。这只能让你找出原因。示例:godbolt.org/z/vnhx3Wj1v-fsanitize=address,undefined
1赞 user4581301 8/24/2023
如果填满数组,则容量计数器可能无法在数组的有效范围内找到零。更糟糕的是,如果将合法的零写入数组会发生什么?最好在放置和移除矢量时跟踪放置在矢量中的项目数量。

答:

1赞 Remy Lebeau 8/24/2023 #1

您展示的代码有很多问题。

为什么要对数组使用 a?您不会在类的实例之间共享它,如果您真的这样做,您的代码会表现得非常糟糕。您应该改用 a。shared_ptrunique_ptr

此外,在 的最后一个循环中,您将向量的每个元素视为向量的索引,但事实并非如此。main()

但是,最重要的是,您似乎不了解容量(分配的元素数)和大小容量内使用的元素数)之间的区别。成员未准确反映要为其分配内存的元素数。并且您在应该使用该成员的地方使用该成员,反之亦然。_capacity_capacity_size

尝试更像这样的东西:

#include <iostream>
#include <memory>
#include <utility>
#include <stdexcept>

template <typename T>
class goodvector {
private:
    size_t _size;
    size_t _capacity;
    std::unique_ptr<T[]> arrptr;

public:
    goodvector() : _size(0), _capacity(5), arrptr(new T[5]) {
        for (size_t i = 0; i < _capacity; ++i) {
            arrptr[i] = T();
        }
    }

    ~goodvector() = default;

    goodvector(const goodvector&) = delete;
    goodvector(goodvector&&) = delete;
    goodvector& operator=(const goodvector&) = delete;
    goodvector& operator=(goodvector&&) = delete;

    size_t capacity() const {
        return _capacity;
    }

    size_t size() const {
        return _size;
    }

    void push_back(T arg) {
        if (_capacity == _size) {
            reserve(_size + 5);
        }
        arrptr[_size] = std::move(arg);
        ++_size; 
    }

    void reserve(size_t sz) {
        if (sz <= _capacity) return;
        std::unique_ptr<T[]> temp(new T[sz]);
        for (size_t i = 0; i < _size; ++i) {
            temp[i] = arrptr[i];
        }
        for (size_t i = _size; i < sz; ++i) {
            temp[i] = T();
        }
        arrptr = std::move(temp);
        _capacity = sz;
    }

    void resize(size_t sz) {
        if (sz == _size) return;
        if (sz < _size) {
            for(size_t i = sz; i < _size; ++i) {
                arrptr[i] = T();
            }
        }
        else {
            reserve(sz);
        }
        _size = sz;
    }

    T operator[](size_t position) const {
        if (position >= _size) {
            throw out_of_range("out of range");
        }
        return arrptr[position];
    }

    void print(size_t position) const {
        if (position >= _size) {
            throw out_of_range("out of range");
        }
        cout << arrptr[position] << endl;
    }

    const T* cbegin() const {
        return arrptr.get();
    }

    T* begin() {
        return arrptr.get();
    }

    const T* cend() const {
        return arrptr.get() + _size;
    }

    T* end() {
        return arrptr.get() + _size;
    }
};

int main() {
    goodvector<int> b;
    b.reserve(30);
    cout << "size " << b.size() << endl << "capacity " << b.capacity() << endl;
    for (int i = 0; i < 30; ++i) {
        b.push_back(42);
    }
    cout << "size after push_back: " << b.size() << endl << "capacity after push_back: " << b.capacity() << endl;
    for (auto iter = b.begin(); iter != b.end(); ++iter) {
        cout << *iter << endl;
    }
}

显然,还有改进的余地(比如不初始化已经初始化自身的数组成员),但这应该给你一个关于你的向量应该如何表现的要点。