Lesson 11 | C++ Dynamic Arrays |
Objective | Understand dynamic arrays with new[] /delete[] and modern RAII alternatives such as std::vector and std::unique_ptr . |
std::vector
In C++ you can obtain dynamically sized storage at run time. Historically this was done with
new[]
and released with delete[]
. In modern C++, the preferred approach is to use
RAII containers such as std::vector<T>
or smart pointers (e.g., std::unique_ptr<T[]>
),
which free memory automatically and add safety features such as bounds-aware access and exception safety.
data
acts as the base address of a dynamically allocated array with
size
elements. Each subscripted access like data[j]
performs pointer arithmetic relative
to this base address.
new[]
(for comparison)
The following minimal example shows legacy-style allocation with new[]
. It compiles, but it’s
easy to get wrong: you must pair new[]
with delete[]
, use the correct type for sizes, and
avoid reading uninitialized elements.
#include <iostream>
#include <vector> // only for later contrast
#include <cassert>
int main() {
using std::cout;
using std::cin;
std::size_t size{};
cout << "Enter array size: ";
cin >> size;
assert(size > 0);
int* data = new int[size]; // allocate size ints
// Initialize values to something meaningful before printing:
for (std::size_t j = 0; j < size; ++j) {
data[j] = static_cast<int>(j);
}
for (std::size_t j = 0; j < size; ++j) {
cout << data[j] << '\t';
}
cout << '\n';
delete[] data; // must use delete[] for arrays
}
data
points to the first element; data[j]
is computed via pointer arithmetic.new
throws std::bad_alloc
on failure (it no longer returns nullptr
in standard builds). A production program should catch this.new[]
must be paired with delete[]
(not plain delete
).std::vector<int>
Prefer std::vector
for resizable arrays. It owns its memory, initializes elements, supports
.size()
, offers bounds-checked access with .at()
, and integrates with algorithms.
#include <iostream>
#include <vector>
#include <numeric> // std::iota
int main() {
using std::cout;
using std::cin;
std::size_t size{};
cout << "Enter array size: ";
cin >> size;
std::vector<int> data(size); // RAII-managed dynamic array
std::iota(data.begin(), data.end(), 0); // fill with 0,1,2,...
for (std::size_t j = 0; j < data.size(); ++j) {
cout << data[j] << '\t';
}
cout << '\n'; // automatic cleanup; no delete[] needed
}
delete[]
.data.at(j)
(throws on error).std::iota
, std::sort
).data
goes out of scope.Some legacy APIs require a raw pointer. Use a smart pointer to keep RAII while honoring the API’s signature.
#include <iostream>
#include <memory> // std::unique_ptr
#include <algorithm>
int main() {
std::size_t size = 8;
auto data = std::make_unique<int[]>(size); // RAII for dynamic arrays
for (std::size_t j = 0; j < size; ++j) data[j] = static_cast<int>(j * j);
// Pass data.get() to functions that need int*.
std::for_each(data.get(), data.get() + size, [](int v){ std::cout << v << '\t'; });
std::cout << '\n';
// No delete[] needed; unique_ptr frees memory automatically.
}
new[]
with delete[]
—never plain delete
.std::vector
, std::unique_ptr
).std::size_t
for sizes/indices to avoid negative values.new[]
arrays can’t be resized; use std::vector::resize
instead.C-style arrays provide no bounds checking and no size tracking. C++ adds powerful abstractions that make dynamic arrays safer and more expressive:
std::vector<T>
— resizable dynamic array (default choice).std::array<T,N>
— fixed-size array with size information at compile time.std::span<T>
— lightweight, non-owning view over a contiguous sequence.std::unique_ptr<T[]>
— owning smart pointer for raw array interoperability.n
, create std::vector<int>
of size n
, fill with i
, print in reverse..at()
and catch the exception on an out-of-range index.std::make_unique<int[]>
, compute prefix sums in-place, and print.
#include <iostream>
#include <cassert>
int main() {
using std::cout;
using std::cin;
std::size_t size{};
cout << "Enter array size: ";
cin >> size;
assert(size > 0);
int* data = new int[size];
for (std::size_t j = 0; j < size; ++j) {
data[j] = static_cast<int>(j);
cout << data[j] << '\t';
}
cout << "\n";
delete[] data;
}
new
.