Реализация своего vector C++, удаление последнего элемента через pop_back()

Рейтинг: 0Ответов: 1Опубликовано: 11.03.2023
#include <iostream>
#include <cstdlib>

namespace s21 {
    template <class T>
    class vector {
        public:
            using value_type = T;
            using reference = T&;
            using const_reference = const T&;
            using iterator = T*;
            using const_iterator = const T*;
            using size_type = std::size_t;
        
        public:
            vector();
            ~vector();
            void push_back(const_reference value);
            const_reference back();
            void pop_back();

        private:
            T *array_;
            size_t size_;
            size_t capacity_;
    };
}

namespace s21 {
    template <class T> 
    vector<T>::vector() : array_(new T[1]), size_(0), capacity_(1) {}

    template <class T> 
    vector<T>::~vector() {
        std::cout << array_[5];
        delete [] array_;
    }

    template <class T>
    void vector<T>::push_back(const_reference value) {
        if (size_ == capacity_) {
            capacity_ += 10;
            T *tmp = new T[capacity_];
            std::copy(array_, array_ + size_, tmp);
            delete [] array_;
            array_ = tmp;
        } 
        array_[size_] = value;
        size_++;
    }

    template <class T>
    typename vector<T>::const_reference vector<T>::back() {
        if (size_ == 0) {
            throw(std::out_of_range("vector is empty"));
        }
        return array_[size_ - 1];
    }

    template <class T>
    void vector<T>::pop_back() {
        if (size_ == 0) {
            throw(std::out_of_range("Vector is empty"));
        }
        size_--;
        array_[size_].~T(); // тут пытаюсь деструктор на последний элемент вызвать, но похоже оно не работает
                            // так как все равно потом к этому элементу можно обратиться
    }
}


int main() {
    s21::vector <int> steck_;
    steck_.push_back(1);
    steck_.push_back(2);
    steck_.push_back(3);
    steck_.push_back(4);
    steck_.push_back(5);
    steck_.push_back(5);
    steck_.push_back(5);
    steck_.pop_back();
    steck_.pop_back();
    steck_.pop_back();
    steck_.pop_back();
    std::cout << steck_.back() << std::endl;
    return 0;
}

Погуглил, кто-то пишет, что достаточно просто уменьшить size, а с самим элементом ничего не делать, другие пишут, что оригинальный vector таки удаляет этот элемент. Нашёл вот такой способ array_[size_].~T(), но судя по всему, он не работает? Я все ещё могу обратиться к как бы удалённым элементам (в деструкторе ~vector() для проверки вывожу элемент, который должен был удалиться).

Ответы

▲ 0

При удалении вашего вектора как такового в его деструкторе у вас вызывается

delete [] array_;

Т.е. будет вызван деструктор для каждого элемента массива. Так имеет ли смысл вызывать деструктор при pop_back(), в особенности рискуя тем, что такой деструктор будет вызван дважды (второй раз при удалении вектора) и для чего-то посложнее int может привести к массе неприятностей? Конечно, можно вызывать деструктор и в pop_back(), но тогда надо принять специальные меры во избежание упомянутых неприятностей.
Как именно этого добиться — отдельный вопрос, в обычном векторе из стандартной библиотеки этим занимается аллокатор.

Теперь об обращении к удаленным... Как вы себе представляете невозможность обращения? Что это вообще значит — удаленный элемент? Особенно простой, типа int, который деструктор не запортит (а вообще ничего не сделает)? Как физическое вырезание куска памяти из платы? :) Память-то на месте, так почему к ней нельзя обратиться? Можно вообще обратиться к памяти по "левому" адресу, просто это будет неопределенное поведение.

Т.е. окончательный ответ на вторую часть вашего вопроса остается открытым, пока мы не утрясем терминологическую путаницу и ваши ожидания. Итак, что такое в вашем представлении "удаленный элемент массива"? В массиве int a[] = { 1,2,3,4} как вы себе представляете удаление элемента 4?