std::vector の関数の中でもよく使う関数ではないかと思います。有名な「capacity が足りない場合は、現在の capacity の値を倍にする」という領域確保の戦略も併せて実装します。
template <typename T> class myvector { ... /** * @brief Appends the given element value to the end of the container. * The new element is initialized as a copy of value. * If the new size() is greater than capacity() then all iterators * and references (including the past-the-end iterator) are invalidated. * Otherwise only the past-the-end iterator is invalidated. * @param[in] value: The value of the element to append. * @throw std::length_error: If new capacity is greater than max_size(). * @throw std::bad_alloc: If malloc() (or realloc()) fails to allocate storage. */ void push_back(const value_type& value) { if (need_twice_capacity()) { reallocation(twice_length(), realloc_switcher()); } new(&heap_[size_]) value_type(value); size_++; } /** * @brief Appends the given element value to the end of the container. * The value is moved into the new element. * If the new size() is greater than capacity() then all iterators * and references (including the past-the-end iterator) are invalidated. * Otherwise only the past-the-end iterator is invalidated. * @param[in,out] value: The value of the element to append. * @throw std::length_error: If new capacity is greater than max_size(). * @throw std::bad_alloc: If malloc() (or realloc()) fails to allocate storage. */ void push_back(value_type&& value) { if (need_twice_capacity()) { reallocation(twice_length(), realloc_switcher()); } new(&heap_[size_]) value_type(std::forward<value_type&&>(value)); size_++; } ... private: /** * @brief Check twice capacity is needed or not. * @return true: Need twice capacity. * false: Not need twice capacity. * @throw std::length_error: If size_ already reaches MAX_SIZE. */ bool need_twice_capacity(void) const { if (size_ >= MAX_SIZE) { throw std::length_error("myvecotr::need_twice_capacity()"); } return (size_ + 1) > capacity_; } /** * @brief Make twice capacity value. * @return New capacity which is twice as current capacity. * If current capacity is 0, then return 1. * @throw std::length_error: If new capacity is greater than the maximum size. */ size_type twice_length(void) const { if (capacity_ > (MAX_SIZE / 2)) { throw std::length_error("myvecotr::twice_length()"); } return capacity_ ? capacity_ * 2 : 1; } ... };twice_length() という capacity の倍の値を計算する関数を用意します。単純に capacity_ の値を倍にしてから std::length_error のチェックをすると、オーバーフローが発生する可能性があります。そのため、倍にする前に std::length_error のチェックをするようにします。
twice_length() の前には need_twice_capacity() という関数を呼びます。これは、capacity を大きくする必要があるかどうかをチェックする関数です。また、size_ + 1 がオーバーフローする場合の対処も行います。
push_back() では、まず need_twice_capacity() で capacity_ を大きくする必要があるかどうかをチェックします。
capacity を大きくする操作は、以前作成した reallocation() を流用可能です。
領域確保に関する操作が終われば、末尾になる要素に対してコンストラクタを呼び、size を1だけ大きくします。
第二引数が左辺値参照の push_back() と右辺値参照の push_back() の違いは、コンストラクタを呼ぶ時に、コピーコンストラクタが呼ばれるか、ムーブコンストラクタが呼ばれるか、という点のみです。
全ソースコード:
https://github.com/suomesta/myvector/tree/master/016
0 件のコメント:
コメントを投稿