我如何在 C++ 中实现 vector 的迭代器插入(const_iterator 位置,InputIterator 首先,InputIterator 最后)?
How can i Implement iterator insert (const_iterator position, InputIterator first, InputIterator last) of vector in c++?
你好,我正在尝试用 C++ 制作向量 class。我想制作下面的一个。你能告诉我怎么做吗?
https://www.cplusplus.com/reference/vector/vector/insert/
std::vector::insert
范围 (3)
模板
迭代器插入(const_iterator位置,InputIterator在前,InputIterator在后);
这是我的代码。如果有错误请告诉我。
#ifndef VECTOR_H
#define VECTOR_H
#include <algorithm>
#include <iostream>
#include <stdexcept>
#include "dsexceptions.h"
template <typename Object>
class Vector
{
public:
explicit Vector(int initSize = 0)
: theSize(initSize), theCapacity(initSize + SPARE_CAPACITY),objects(nullptr)
{
(objects = new Object[theCapacity]);
for(int k=0; k<theSize; ++k)
{
objects[k] = 0;
}
}
Vector(const Vector& rhs)
: theSize(rhs.theSize), theCapacity( rhs.theCapacity ), objects( nullptr)
{
objects = new Object[theCapacity];
for (int k = 0; k < theSize; ++k)
objects[k] = rhs.objects[k];
}
Vector& operator= (const Vector& rhs)
{
Vector copy = rhs;
std::swap(*this, copy);
return *this;
}
~Vector()
{
delete[] objects;
}
Vector(Vector&& rhs)
: theSize{ rhs.theSize }, theCapacity{ rhs.theCapacity }, objects{ rhs.objects }
{
rhs.objects = nullptr;
rhs.theSize = 0;
rhs.theCapacity = 0;
}
Vector& operator= (Vector&& rhs)
{
std::swap(theSize, rhs.theSize);
std::swap(theCapacity, rhs.theCapacity);
std::swap(objects, rhs.objects);
return *this;
}
bool empty() const
{
return size() == 0;
}
int size() const
{
return theSize;
}
int capacity() const
{
return theCapacity;
}
Object& operator[](int index)
{
#ifndef NO_CHECK
if (index < 0 || index >= size())
throw ArrayIndexOutOfBoundsException{ };
#endif
return objects[index];
}
const Object& operator[](int index) const
{
#ifndef NO_CHECK
if (index < 0 || index >= size())
throw ArrayIndexOutOfBoundsException{ };
#endif
return objects[index];
}
void resize(int newSize)
{
if (newSize > theCapacity)
reserve(newSize * 2);
theSize = newSize;
}
void reserve(int newCapacity)
{
if (newCapacity < theSize)
return;
Object* newArray = new Object[newCapacity];
for (int k = 0; k < theSize; ++k)
newArray[k] = std::move(objects[k]);
theCapacity = newCapacity;
std::swap(objects, newArray);
delete[] newArray;
}
// Stacky stuff
void push_back(const Object& x)
{
if (theSize == theCapacity)
reserve(2 * theCapacity + 1);
objects[theSize++] = x;
}
// Stacky stuff
void push_back(Object&& x)
{
if (theSize == theCapacity)
reserve(2 * theCapacity + 1);
objects[theSize++] = std::move(x);
}
void pop_back()
{
if (empty())
throw UnderflowException{ };
--theSize;
}
const Object& back() const
{
if (empty())
throw UnderflowException{ };
return objects[theSize - 1];
}
// Iterator stuff: not bounds checked
typedef Object* iterator;
typedef const Object* const_iterator;
iterator begin()
{
return &objects[0];
}
const_iterator begin() const
{
return &objects[0];
}
iterator end()
{
return &objects[size()];
}
const_iterator end() const
{
return &objects[size()];
}
static const int SPARE_CAPACITY = 2;
/*************************************************************************/
/*************************************************************************/
iterator insert(const_iterator position, const Object& val)
{
if (theSize == theCapacity)
{
reserve(2 * theCapacity + 1);
}
int index = position - objects;
for (int i = theSize - 1; i >= index; --i)
objects[i + 1] = objects[i];
objects[index] = val;
theSize++;
return &objects;
}
iterator insert(const_iterator position, Object&& val)
{
if (theSize == theCapacity)
{
reserve(2 * theCapacity + 1);
}
int index = position - objects;
for (int i = theSize-1; i>=index; --i)
objects[i+1] = objects[i];
objects[index] = std::move(val);
theSize++;
return objects;
}
那个特定的重载是一件棘手的事情,因为它要求您接受最通用的迭代器类型,但人们会期望其他迭代器类型具有更好的性能。
天真的方法是从 first
循环到 last
,insert
遍历每个元素。
template<typename InputIterator>
void insert(const_iterator position, InputIterator first, InputIterator last) {
for (; first != last; ++first) {
position = insert(position, *first);
}
}
然而,这可能需要多次重新分配。你 必须 使用 InputIterator 来做到这一点,因为它们不一定支持多次传递,但保留足够的 [=36] 真的很有用=]提前。
您可以有一个仅适用于 ForwardIterators 的额外重载,它支持多次传递,因此您可以知道需要多少容量。
对于 C++20,这可以通过使用受限模板类型进行重载来完成
template<std::input_iterator InputIterator>
void insert(const_iterator position, InputIterator first, InputIterator last) {
for (; first != last; ++first) {
position = insert(position, *first);
}
}
template<std::forward_iterator ForwardIterator>
void insert(const_iterator position, ForwardIterator first, ForwardIterator last) {
auto requiredCapacity = theSize + std::distance(first, last);
if (requiredCapacity > theCapacity) {
auto index = std::distance(objects, position);
reserve(requiredCapacity);
position = objects + index;
}
for (; first != last; ++first) {
position = insert(position, *first);
}
}
在 C++20 之前,您可以将 public insert
分派到两个私有实现之一
template<typename InputIterator>
void insert(const_iterator position, InputIterator first, InputIterator last) {
insert_impl(position, first, last, std::iterator_traits<InputIterator>::iterator_category{});
}
template<typename InputIterator>
void insert_impl(const_iterator position, InputIterator first, InputIterator last, std::input_iterator_tag) {
for (; first != last; ++first) {
position = insert(position, *first);
}
}
template<typename ForwardIterator>
void insert_impl(const_iterator position, ForwardIterator first, ForwardIterator last, std::forward_iterator_tag) {
auto requiredCapacity = theSize + std::distance(first, last);
if (requiredCapacity > theCapacity) {
auto index = std::distance(objects, position);
reserve(requiredCapacity);
position = objects + index;
}
for (; first != last; ++first) {
position = insert(position, *first);
}
}
你好,我正在尝试用 C++ 制作向量 class。我想制作下面的一个。你能告诉我怎么做吗?
https://www.cplusplus.com/reference/vector/vector/insert/
std::vector::insert
范围 (3)
模板
迭代器插入(const_iterator位置,InputIterator在前,InputIterator在后);
这是我的代码。如果有错误请告诉我。
#ifndef VECTOR_H
#define VECTOR_H
#include <algorithm>
#include <iostream>
#include <stdexcept>
#include "dsexceptions.h"
template <typename Object>
class Vector
{
public:
explicit Vector(int initSize = 0)
: theSize(initSize), theCapacity(initSize + SPARE_CAPACITY),objects(nullptr)
{
(objects = new Object[theCapacity]);
for(int k=0; k<theSize; ++k)
{
objects[k] = 0;
}
}
Vector(const Vector& rhs)
: theSize(rhs.theSize), theCapacity( rhs.theCapacity ), objects( nullptr)
{
objects = new Object[theCapacity];
for (int k = 0; k < theSize; ++k)
objects[k] = rhs.objects[k];
}
Vector& operator= (const Vector& rhs)
{
Vector copy = rhs;
std::swap(*this, copy);
return *this;
}
~Vector()
{
delete[] objects;
}
Vector(Vector&& rhs)
: theSize{ rhs.theSize }, theCapacity{ rhs.theCapacity }, objects{ rhs.objects }
{
rhs.objects = nullptr;
rhs.theSize = 0;
rhs.theCapacity = 0;
}
Vector& operator= (Vector&& rhs)
{
std::swap(theSize, rhs.theSize);
std::swap(theCapacity, rhs.theCapacity);
std::swap(objects, rhs.objects);
return *this;
}
bool empty() const
{
return size() == 0;
}
int size() const
{
return theSize;
}
int capacity() const
{
return theCapacity;
}
Object& operator[](int index)
{
#ifndef NO_CHECK
if (index < 0 || index >= size())
throw ArrayIndexOutOfBoundsException{ };
#endif
return objects[index];
}
const Object& operator[](int index) const
{
#ifndef NO_CHECK
if (index < 0 || index >= size())
throw ArrayIndexOutOfBoundsException{ };
#endif
return objects[index];
}
void resize(int newSize)
{
if (newSize > theCapacity)
reserve(newSize * 2);
theSize = newSize;
}
void reserve(int newCapacity)
{
if (newCapacity < theSize)
return;
Object* newArray = new Object[newCapacity];
for (int k = 0; k < theSize; ++k)
newArray[k] = std::move(objects[k]);
theCapacity = newCapacity;
std::swap(objects, newArray);
delete[] newArray;
}
// Stacky stuff
void push_back(const Object& x)
{
if (theSize == theCapacity)
reserve(2 * theCapacity + 1);
objects[theSize++] = x;
}
// Stacky stuff
void push_back(Object&& x)
{
if (theSize == theCapacity)
reserve(2 * theCapacity + 1);
objects[theSize++] = std::move(x);
}
void pop_back()
{
if (empty())
throw UnderflowException{ };
--theSize;
}
const Object& back() const
{
if (empty())
throw UnderflowException{ };
return objects[theSize - 1];
}
// Iterator stuff: not bounds checked
typedef Object* iterator;
typedef const Object* const_iterator;
iterator begin()
{
return &objects[0];
}
const_iterator begin() const
{
return &objects[0];
}
iterator end()
{
return &objects[size()];
}
const_iterator end() const
{
return &objects[size()];
}
static const int SPARE_CAPACITY = 2;
/*************************************************************************/
/*************************************************************************/
iterator insert(const_iterator position, const Object& val)
{
if (theSize == theCapacity)
{
reserve(2 * theCapacity + 1);
}
int index = position - objects;
for (int i = theSize - 1; i >= index; --i)
objects[i + 1] = objects[i];
objects[index] = val;
theSize++;
return &objects;
}
iterator insert(const_iterator position, Object&& val)
{
if (theSize == theCapacity)
{
reserve(2 * theCapacity + 1);
}
int index = position - objects;
for (int i = theSize-1; i>=index; --i)
objects[i+1] = objects[i];
objects[index] = std::move(val);
theSize++;
return objects;
}
那个特定的重载是一件棘手的事情,因为它要求您接受最通用的迭代器类型,但人们会期望其他迭代器类型具有更好的性能。
天真的方法是从 first
循环到 last
,insert
遍历每个元素。
template<typename InputIterator>
void insert(const_iterator position, InputIterator first, InputIterator last) {
for (; first != last; ++first) {
position = insert(position, *first);
}
}
然而,这可能需要多次重新分配。你 必须 使用 InputIterator 来做到这一点,因为它们不一定支持多次传递,但保留足够的 [=36] 真的很有用=]提前。
您可以有一个仅适用于 ForwardIterators 的额外重载,它支持多次传递,因此您可以知道需要多少容量。
对于 C++20,这可以通过使用受限模板类型进行重载来完成
template<std::input_iterator InputIterator>
void insert(const_iterator position, InputIterator first, InputIterator last) {
for (; first != last; ++first) {
position = insert(position, *first);
}
}
template<std::forward_iterator ForwardIterator>
void insert(const_iterator position, ForwardIterator first, ForwardIterator last) {
auto requiredCapacity = theSize + std::distance(first, last);
if (requiredCapacity > theCapacity) {
auto index = std::distance(objects, position);
reserve(requiredCapacity);
position = objects + index;
}
for (; first != last; ++first) {
position = insert(position, *first);
}
}
在 C++20 之前,您可以将 public insert
分派到两个私有实现之一
template<typename InputIterator>
void insert(const_iterator position, InputIterator first, InputIterator last) {
insert_impl(position, first, last, std::iterator_traits<InputIterator>::iterator_category{});
}
template<typename InputIterator>
void insert_impl(const_iterator position, InputIterator first, InputIterator last, std::input_iterator_tag) {
for (; first != last; ++first) {
position = insert(position, *first);
}
}
template<typename ForwardIterator>
void insert_impl(const_iterator position, ForwardIterator first, ForwardIterator last, std::forward_iterator_tag) {
auto requiredCapacity = theSize + std::distance(first, last);
if (requiredCapacity > theCapacity) {
auto index = std::distance(objects, position);
reserve(requiredCapacity);
position = objects + index;
}
for (; first != last; ++first) {
position = insert(position, *first);
}
}