| 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.