很抱歉,如果以前已经解决过这个问题。我知道如何使用C和Java而不是C ++来做到这一点。在不使用包含Vector的现有类的情况下,给定以下代码,如何增加数组的大小?
数组扩展和对数组的分配在带有大写注释的push()中进行。
编辑:正如我在下面的评论中提到的,这是一个有关手动重新分配数组而不是使用std :: vector或“动态数组”的问题。
Line.h
res = tf.zeros((3,19,19,12))
res[0][1][1][(2*4):(2*4 + 4)] = 1
res[image][x][y][(i*4):(i*4+4)] = 1
Main.cpp
#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;
};
答案 0 :(得分:4)
简单的答案是,在这种情况下,您应始终使用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
答案 1 :(得分:3)
基本上,唯一的方法是使用动态数组(使用new[]
创建的动态数组)并创建全新的动态数组并复制(或移动) )从旧的 array 到新的对象。
类似这样的东西:
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
)中的元素本身是 exception,则 exception safety 仅将是 complete 。 复制或移动时安全。
但是,这不涉及有效分配。 std::vector
将过度分配,因此它不必对每个新元素都这样做。这段代码还遗漏了std::vector
会采用的其他技巧(例如分配未初始化内存,以及在需要/丢弃时手动构造/破坏元素)。
答案 2 :(得分:2)
除了分配一个新数组,复制现有值并delete []
旧值之外,基本上别无选择。这就是向量通过乘数因子进行重新分配的原因(例如,每个重新分配的大小都会增加一倍)。这是您要使用标准库结构而不是重新实现的原因之一。
答案 3 :(得分:0)
保持简单
在我看来,在这种情况下,最好在CPoint
中使用CLine
的链表:
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;
};