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 件のコメント:
コメントを投稿