Это более или менее то, что делает std::vector
, хотя он реализован с гораздо большей универсальностью, поэтому новичку немного сложно прочитать исходную информацию о любой реализации библиотеки (особенно с учетом обычно кошмарных соглашений об именах). используется в стандартном коде библиотеки).
Вот первый динамический массив ребенка:
class MyArray
{
float * buf;
std::size_t size;
public:
explicit MyArray(std::size_t s) : buf(new float[s]), size(s) { }
~MyArray() { delete[] buf; }
// Copying and reassigning is tricky! We disallow it for now.
MyArray(MyArray const &) = delete;
MyArray & operator=(MyArray const &) = delete;
std::size_t size() const { return size; }
float & operator[](std::size_t i) { return buf[i]; }
float const & operator[](std::size_t i) const { return buf[i]; }
};
Это безопасно для исключений: единственное время, когда может произойти исключение, находится в списке инициализатора конструктора, и есть только один такой случай (new
). Если произойдет исключение, ничто не будет пропущено, поскольку в этот момент больше ничего не было выделено.
Использование:
MyArray a(20);
a[4] = 6.3;
Более продвинутая версия будет включать функцию resize()
; для этого вам нужно выделить и скопировать (скажем):
void resize(std::size_t n)
{
float * tmp = new float[n];
std::copy(buf, buf + std::min(size, n), tmp); // I assume this doesn't throw
delete[] buf;
buf = tmp;
size = n;
}
Как только вы поймете, что должен делать оператор присваивания, вы можете использовать идею, очень похожую на идею resize()
, чтобы назначить один MyArray
другому.