在C++中手动调整数组大小
Manually resize array in C++
如果之前已经讨论过,我很抱歉。我知道如何做到这一点是C和Java,但不是C++。如果不使用包含Vector的预先存在的类,在给定以下代码的情况下,如何增加数组的大小?
数组的扩展和分配在push((中进行,用全大写注释进行注释。
编辑:正如我在下面的评论中提到的,这是一个关于手动重新分配数组而不是使用std::vector或"动态数组"的问题
第h行
#include <iostream>
#include "Point.h"
using namespace std;
class Line {
public:
Line();
virtual ~Line();
// TAKE IN NEW POINT, INCREASE THE ARRAY SIZE AND ADD NEW POINT TO THE END OF THE ARRAY
void push(const Point& p);
private:
unsigned int index; // size of "points" array
Point* points;
};
主要.cpp
#include <iostream>
#include "Point.h"
#include "Line.h"
using namespace std;
int main() {
int x, y;
int size; // Some user defined size for the array
Line line;
Point a[size]; // Some points that are already filled
// Push the data in a[] to the variable "line"
for(int i = 0; i < size; i++){
// Increase array size of Point* points in variable line and add a[i] to the end of the array
line.push(points[i]);
}
return 0;
}
简单的答案是,在这种情况下,您应该始终使用std::vector。然而,解释一下为什么会这样可能会很有用。所以,让我们考虑一下在没有std::vector的情况下如何实现这一点,这样你就可以明白为什么要使用std::vector:
// Naive approach
Line::push(const Point& p)
{
Point* new_points = new Points[index + 1];
std::copy(std::make_move_iterator(points), std::make_move_iterator(points+index), new_points);
new_points[index] = p;
delete[] points;
points = new_points;
index += 1;
}
这种方法有很多问题。每次插入条目时,我们都被迫重新分配和移动整个数组。然而,向量将预先分配一个保留,并为每个插入使用保留之外的空间,只有在超过保留限制时才重新分配空间。就性能而言,这个平均向量将远远优于代码,因为不必要地分配和移动数据所花费的时间将减少。接下来是异常问题,此实现没有异常保证,因为std::vector为您提供了强大的异常保证:https://en.wikipedia.org/wiki/Exception_safety.为您的类实现一个强大的异常保证绝非易事,然而,如果您按照这样的std::vector实现了这一点,您就会自动得到它
Line::push(const Point& p)
{
points.push_back(p);
}
您的方法还有其他更微妙的问题,您的类没有定义复制或赋值运算符,因此会生成编译器生成的浅复制版本,这意味着如果有人复制了您的类,则分配的成员将被删除两次。要解决这个问题,您需要遵循C++11之前的3范式规则和C++11之后的5规则:https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming(。然而,如果您使用向量,则不需要这些,因为您将受益于零规则,并且能够依赖编译器生成的默认值:https://blog.rmf.io/cxx11/rule-of-zero
本质上,唯一的方法是使用动态数组(使用new[]
创建的数组(,并创建一个全新的动力学数组组复制(或移动(到新数组。
类似这样的东西:
class Line {
public:
Line(): index(0), points(nullptr) {} // initialize
virtual ~Line() { delete[] points; } // Clean up!
void push(const Point& p)
{
// create new array one element larger than before
auto new_points = new Point[index + 1];
// copy old elements to new array (if any)
for(unsigned int p = 0; p < index; ++p)
new_points[p] = points[p];
new_points[index] = p; // then add our new Point to the end
++index; // increase the recorded number of elements
delete[] points; // out with the old
points = new_points; // in with the new
}
private:
unsigned int index; // size of "points" array
Point* points;
};
但这种方法效率很低。要做好这件事相当复杂。以这种方式做事的主要问题是:
- 异常安全-在引发异常时避免内存泄漏
- 分配-避免每次都要重新分配(和重新复制(
- 移动语义-利用某些对象被移动的能力比它们被复制的效率高得多
更好的版本:
class Line {
public:
Line(): index(0) {} // initialize
virtual ~Line() { } // No need to clean up because of `std::unique_ptr`
void push(const Point& p)
{
// create new array one element larger than before
auto new_points = std::unique_ptr<Point[]>(new Point[index + 1]);
// first add our new Point to the end (in case of an exception)
new_points[index] = p;
// then copy/move old elements to new array (if any)
for(unsigned int p = 0; p < index; ++p)
new_points[p] = std::move(points[p]); // try to move else copy
++index; // increase the recorded number of elements
std::swap(points, new_points); // swap the pointers
}
private:
unsigned int index; // size of "points" array
std::unique_ptr<Point[]> points; // Exception safer
};
这涉及到异常安全和(在某种程度上但并非完全(移动语义。但是,必须指出的是,只有当被复制或移动时,存储在数组中的元素(类型Point
(本身是异常安全,例外安全才会是完整。
但这并不涉及有效分配。std::vector
将过度分配,因此不必对每个新元素都这样做。此代码还错过了std::vector
可能使用的其他一些技巧(如分配未初始化的内存,以及在需要/丢弃元素时手动构建/销毁元素(。
您基本上没有办法,只能分配一个新数组,复制里面的现有值,并delete []
旧数组。这就是矢量通过乘法因子进行重新分配的原因(比如每次重新分配都会使大小翻倍(。这就是您希望使用标准库结构而不是重新实现的原因之一。
保持简单
在我看来,在这种情况下,最好在CLine
:中使用CPoint
的链表
struct CPoint
{
int x = 0, y = 0;
CPoint * m_next = nullptr;
};
class CLine
{
public:
CLine() {};
virtual ~CLine()
{
// Free Linked-List:
while (m_points != nullptr) {
m_current = m_points->m_next;
delete m_points;
m_points = m_current;
}
};
// TAKE IN NEW POINT, INCREASE THE ARRAY SIZE AND ADD NEW POINT TO THE END OF THE ARRAY
void push(const CPoint& p)
{
m_current = (((m_points == nullptr) ? (m_points) : (m_current->m_next)) = new CPoint);
m_current->m_x = p.m_x;
m_current->m_y = p.m_y;
m_index++;
};
private:
unsigned int m_index = 0; // size of "points" array
CPoint * m_points = nullptr, * m_current = nullptr;
};
或者,使用智能指针更好:
#include <memory>
struct CPoint
{
int m_x = 0, m_y = 0;
std::shared_ptr<CPoint> m_next;
};
class CLine
{
public:
CLine() {};
virtual ~CLine() {}
// TAKE IN NEW POINT, INCREASE THE ARRAY SIZE AND ADD NEW POINT TO THE END OF THE ARRAY
void push(const CPoint& p)
{
m_current = (((m_points == nullptr) ? (m_points) : (m_current->m_next)) = std::make_shared<CPoint>());
m_current->m_x = p.m_x;
m_current->m_y = p.m_y;
m_index++;
};
private:
unsigned int m_index = 0; // size of "points" array
std::shared_ptr<CPoint> m_points, m_current;
};
- 为char数组调整zlib-zpipe
- 当您在此单词中搜索单词时调整字符数组的大小?
- 调整大小和复制哈希表数组中的元素
- 尝试将数组大小调整为 -1
- 将动态分配的数组的大小调整为较小的大小C++
- 我的C++程序有问题.涉及动态调整整数数组的大小
- 通过新的后传递后创建的动态数组的错误以调整函数
- 在哈希表中调整字符串数组的大小
- 与教科书上关于未调整大小的数组初始化C++句子的混淆
- 调整双指针数组C++大小
- 调整结构/字符数组的大小(以减少内存使用)
- 我的数组大小调整代码在新数据上引发异常[size_t]
- 如何使用3D char数组调整双指针2D char阵列的大小
- C++ 数组将所有值调整相同的量
- 调整动态数组大小时保留用户输入的值的问题
- C++我需要能够调整动态数组的大小
- 如何调整属于类的唯一指针的字符数组的大小.它必须在程序的整个生命周期中保持活力
- 调整小于连续数组的 C++ 矢量大小
- 我需要调整指针数组的大小
- 动态数组调整大小函数问题