(C++) Simple implementation of vector

foreword

For some operations such as imitating the standard library that I try to write. Never feel how nb you have achieved, you are a younger brother in front of the standard libraries of major compilers.

So don't think that the basic linear table operations written in your data structure class are clinker. You can only say that there are people outside the people, and there are mountains outside the mountains.

Basic considerations for implementing a vector

  • Data type declaration
  • Constructor
  • Destructor
  • copy move copy move
  • iterator iterators
  • Accessor accessor
  • capacity capacity
  • Modifier modifier
  • Append and delete do_back at the end
  • operator overloading
  • Etc., etc

Code

This article refers to the implementation of the simple vector of LH_Mouse, as a note and homework.

Base version of LH_Mouse

How complicated can a std::vector be written by hand? _哔哩哔哩_bilibili

This is just a simple version that can be considered in a short time ~

#include <stddef.h>

#include <iostream>
#include <string>

namespace my {
    
    
template <class ValueT>
class vector {
    
    
public:
    using value_type = ValueT;
    using reference = ValueT&;
    using const_reference = const ValueT&;
    using iterator = ValueT*;
    using const_iterator = const ValueT*;
    using size_type = ::size_t;
    // 迭代器相减
    using difference_type = ::ptrdiff_t;

private:
    ValueT* m_data;
    ::size_t m_size;
    ::size_t m_capacity;

public:
    // 默认无参构造
    constexpr vector() noexcept : m_data(), m_size(), m_capacity() {
    
    
    }

    // 内存是vector自己管理的
    // 只想销毁对象
    ~vector() {
    
    
        this->clear();
        ::operator delete(this->m_data);
    }

    // 拷贝构造
    vector(const vector& rhs) {
    
    
        // 注意 operator new 会抛出异常
        this->m_data = static_cast<ValueT*>(
            ::operator new(rhs.m_capacity * sizeof(ValueT)));

        this->m_size = 0;
        this->m_capacity = rhs.m_capacity;
        try {
    
    
            for (::size_t k = 0; k < rhs->m_size; k += 1) {
    
    
                // placement new
                // new时考虑异常
                ::new (&this->m_data[k]) ValueT(rhs.m_data[k]);
                this->m_size += 1;
            }
        } catch (...) {
    
    
            for (::size_t k = 0; k < this->m_size; k += 1) {
    
    
                this->m_data[k].~ValueT();
            }
            ::operator delete(this->m_data);
            // 将异常重新抛出
            throw;
        }
    }

    // 移动构造
    vector(vector&& rhs) {
    
    
        this->m_data = rhs.m_data;
        this->m_size = rhs.m_size;
        this->m_capacity = rhs.m_capacity;

        rhs.m_data = nullptr;
        rhs.m_size = 0;
        rhs.m_capacity = 0;
    }

    vector& operator=(const vector& rhs) {
    
    
        return *this;
    }
    vector& operator=(vector&& rhs) {
    
    
        return *this;
    }

public:  // 涉及到指针的,需要考虑const版本
    // iterators
    iterator begin() noexcept {
    
    
        return this->m_data;
    }

    const_iterator begin() const noexcept {
    
    
        return this->m_data;
    }

    iterator end() {
    
    
        return this->m_data + this->m_size;
    }

    const_iterator end() const {
    
    
        return this->m_data + this->m_size;
    }

    // accessor
    value_type* data() noexcept {
    
    
        return this->data;
    }

    const value_type* data() const noexcept {
    
    
        return this->m_data;
    }

    size_type size() const noexcept {
    
    
        return this->m_size;
    }

    size_type capacity() const noexcept {
    
    
        return this->m_capacity;
    }

    bool empty() const noexcept {
    
    
        return this->m_size == 0;
    }

    // modifier
    void clear() noexcept {
    
    
        for (::size_t k = 0; k < this->m_size; k += 1) {
    
    
            this->m_data[k].~ValueT();
        }
        this->m_size = 0;
    }

    void pop_back() noexcept {
    
    
        // 保证size>0
        assert(!this->empty());

        ::size_t k = this->m_size - 1;
        this->m_data[k].~ValueT();
        this->m_size += -1;
    }

    void push_back(const ValueT& value) {
    
    
        this->emplace_back(value);
    }

    void push_back(ValueT&& value) {
    
    
        this->emplace_back(::std::move(value));
    }

    template <typename... Args>
    reference emplace_back(Args&&... args) {
    
    
        if (this->m_size < this->m_capacity) {
    
    
            // `data` can not be null
            ::size_t k = this->m_size;
            ::new (&this->m_data[k]) ValueT(::std::forward<Args>(args)...);
            this->m_size += 1;
            return this->m_data[k];
        }

        // 此时 size == capacity
        // 扩容1.5倍
        ::size_t new_capacity = this->m_size + 1;
        new_capacity |= this->m_size / 2;
        ::size_t new_size = 0;
        auto new_data =
            static_cast<ValueT*>(::operator new(new_capacity * sizeof(ValueT)));

        try {
    
    
            for (::size_t k = 0; k < this->m_size; k += 1) {
    
    
                // placement new
                // new时考虑异常
                ::new (&new_data[k]) ValueT(::std::move(this->m_data[k]));
                new_size += 1;
            }

            ::new (&new_data[new_size]) ValueT(::std::forward<Args>(args)...);
            new_size += 1;

        } catch (...) {
    
    
            for (::size_t k = 0; k < new_size; k += 1) {
    
    
                new_data[k].~ValueT();
            }
            ::operator delete(new_data);
            // 将异常重新抛出
            throw;
        }

        // 将原数据析构
        this->clear();
        ::operator delete(this->m_data);

        this->m_data = new_data;
        this->m_size = new_size;
        this->m_capacity = new_capacity;
        return new_data[new_size];
    }
};
}  // namespace my

int main() {
    
    
    ::my::vector<::std::string> vec;

    vec.push_back("hello");
    vec.emplace_back();
    vec.emplace_back("hello", 4);

    // 标准不禁止
    // vec.emplace_back(vec[0]);

    for (const auto& str : vec) {
    
    
        ::std::cout << str << ::std::endl;
    }

    return 0;
}

simple improvement

Really, the poster feels that Miaomiao's writing is already very good and streamlined. Personally, I just made simple additions and notes.

For example, the assignment operation is supplemented, and the function function of destructor is simply encapsulated.


Note that there are still many situations that have not been considered here. If you have to consider your personal ability, you can only write ugly code with extremely low efficiency and high redundancy.

  • If you consider constructing an iterator as a parameter
    • What to do with iterators that can only be accessed once
  • The elements inserted during expansion are the elements of the original sequence itself
    • An error occurred when moving to a new space during capacity expansion
  • Some new operations do not consider exceptions
  • Etc., etc
#include <stddef.h>

#include <iostream>
#include <string>

namespace my {
    
    
template <class ValueT>
class vector {
    
    
public:
    using value_type = ValueT;
    using reference = ValueT&;
    using const_reference = const ValueT&;
    using iterator = ValueT*;
    using const_iterator = const ValueT*;
    using size_type = ::size_t;
    // 迭代器相减
    using difference_type = ::ptrdiff_t;

private:
    ValueT* m_data;
    ::size_t m_size;
    ::size_t m_capacity;

public:
    // 默认无参构造
    constexpr vector() noexcept : m_data(), m_size(), m_capacity() {
    
    
    }

    // 内存是vector自己管理的
    // 只想销毁对象
    ~vector() {
    
    
        this->destruct_this();
    }

    // 拷贝构造
    vector(const vector& rhs) {
    
    
        // 注意 operator new 会抛出异常
        this->m_data = static_cast<ValueT*>(
            ::operator new(rhs.m_capacity * sizeof(ValueT)));
        this->m_size = 0;
        this->m_capacity = rhs.m_capacity;

        try {
    
    
            for (::size_t k = 0; k < rhs->m_size; k += 1) {
    
    
                // new时考虑异常
                ::new (&this->m_data[k]) ValueT(rhs.m_data[k]);
                this->m_size += 1;
            }
        } catch (...) {
    
    
            destruct_this();
            throw;
        }
    }

    // 移动构造
    vector(vector&& rhs) {
    
    
        this->m_data = rhs.m_data;
        this->m_size = rhs.m_size;
        this->m_capacity = rhs.m_capacity;

        rhs.m_data = nullptr;
        rhs.m_size = 0;
        rhs.m_capacity = 0;
    }

    // 偷懒的写法
    vector& operator=(const vector& rhs) {
    
    
        auto tmp = rhs;
        using ::std::swap;
        swap(tmp, *this);
        return *this;
    }

    vector& operator=(vector&& rhs) {
    
    
        auto tmp = ::std::move(rhs);
        using ::std::swap;
        swap(tmp, *this);
        return *this;
    }

public:  // 涉及到指针的,需要考虑const版本
    // iterators
    iterator begin() noexcept {
    
    
        return this->m_data;
    }

    const_iterator begin() const noexcept {
    
    
        return this->m_data;
    }

    iterator end() {
    
    
        return this->m_data + this->m_size;
    }

    const_iterator end() const {
    
    
        return this->m_data + this->m_size;
    }

    // accessor
    value_type* data() noexcept {
    
    
        return this->data;
    }

    const value_type* data() const noexcept {
    
    
        return this->m_data;
    }

    size_type size() const noexcept {
    
    
        return this->m_size;
    }

    size_type capacity() const noexcept {
    
    
        return this->m_capacity;
    }

    bool empty() const noexcept {
    
    
        return this->m_size == 0;
    }

    // modifier
    void clear() noexcept {
    
    
        destruct_len(this->m_data, this->m_size);
        this->m_size = 0;
    }

    void pop_back() noexcept {
    
    
        // 保证size>0
        assert(!this->empty());

        ::size_t k = this->m_size - 1;
        this->m_data[k].~ValueT();
        this->m_size += -1;
    }

    // 调用 emplace_back
    void push_back(const ValueT& value) {
    
    
        this->emplace_back(value);
    }

    void push_back(ValueT&& value) {
    
    
        this->emplace_back(::std::move(value));
    }

    // 注意要使用完美转发
    template <typename... Args>
    reference emplace_back(Args&&... args) {
    
    
        if (this->m_size < this->m_capacity) {
    
    
            ::size_t k = this->m_size;
            ::new (&this->m_data[k]) ValueT(::std::forward<Args>(args)...);
            this->m_size += 1;
            return this->m_data[k];
        }

        // 此时 size == capacity
        // 扩容1.5倍
        ::size_t new_capacity = this->m_size + 1;
        new_capacity += this->m_size / 2;
        ::size_t new_size = 0;
        auto new_data =
            static_cast<ValueT*>(::operator new(new_capacity * sizeof(ValueT)));

        try {
    
    
            for (::size_t k = 0; k < this->m_size; k += 1) {
    
    
                // 并不是所有情况下的移动都是合理的
                ::new (&new_data[k]) ValueT(::std::move(this->m_data[k]));
                new_size += 1;
            }

            ::new (&new_data[new_size]) ValueT(::std::forward<Args>(args)...);
            new_size += 1;
        } catch (...) {
    
    
            destruct_len(new_data, new_size);
            ::operator delete(new_data);
            // 将异常重新抛出
            throw;
        }

        // 将原数据析构
        // 如果上面抛出异常了,这里可能把原数据全清了
        this->destruct_this();
        // 接管所有权
        this->m_data = new_data;
        this->m_size = new_size;
        this->m_capacity = new_capacity;
        return new_data[new_size];
    }

private:
    // 其实是析构的一个抽象
    void destruct_this() noexcept {
    
    
        this->clear();
        ::operator delete(this->m_data);
    }

    void destruct_len(ValueT* pdata, ::size_t len) noexcept {
    
    
        for (::size_t k = 0; k < len; k += 1) {
    
    
            pdata[k].~ValueT();
        }
    }
};
}  // namespace my

int main() {
    
    
    ::my::vector<::std::string> vec;

    vec.push_back("hello");
    vec.emplace_back();
    vec.emplace_back("hello", 4);

    // 标准不禁止
    // vec.emplace_back(vec[0]);

    for (const auto& str : vec) {
    
    
        ::std::cout << str << ::std::endl;
    }

    return 0;
}



END

Guess you like

Origin blog.csdn.net/CUBE_lotus/article/details/131387734