Skip to content

🚫 Modern Arrays — Stop Using C-arrays!

C-style arrays (int arr[]) là legacy. Modern C++ dùng std::vectorstd::array — an toàn hơn và mạnh mẽ hơn.

Vấn đề với C-arrays

1. Không biết size

cpp
void process(int arr[]) {
    // ❌ Không có cách nào biết size của arr!
    // sizeof(arr) = sizeof(pointer), KHÔNG phải array size
}

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    process(arr);  // arr decays to pointer!
    return 0;
}

2. Array Decay

cpp
int arr[5] = {1, 2, 3, 4, 5};

std::cout << sizeof(arr) << std::endl;  // 20 (5 * sizeof(int))

// Khi pass to function, DECAYS to pointer
void func(int* p) {
    std::cout << sizeof(p) << std::endl;  // 8 (pointer size)
}
func(arr);  // Lost size information!

3. No bounds checking

cpp
int arr[5] = {1, 2, 3, 4, 5};

arr[10] = 100;  // ❌ No error! Buffer overflow!
arr[-1] = 0;    // ❌ No error! Undefined behavior!

4. Cannot copy/assign

cpp
int a[5] = {1, 2, 3, 4, 5};
int b[5];

// b = a;  // ❌ Error: cannot assign arrays

// Phải copy manually
for (int i = 0; i < 5; ++i) {
    b[i] = a[i];
}

5. No iterators/algorithms

cpp
int arr[5] = {5, 2, 8, 1, 9};

// ❌ Không thể dùng range-based for trực tiếp với function params
// ❌ Không có .begin(), .end(), .size()

// Phải dùng C-style:
for (int i = 0; i < 5; ++i) {
    std::cout << arr[i] << " ";
}

std::array — Fixed-size Array (C++11)

std::array là wrapper cho C-array với đầy đủ STL interface.

cpp
#include <array>
#include <iostream>
#include <algorithm>

int main() {
    // Declaration (size must be compile-time constant)
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    
    // ✅ Knows its size
    std::cout << "Size: " << arr.size() << std::endl;  // 5
    
    // ✅ Bounds checking
    std::cout << arr.at(2) << std::endl;   // 3
    // arr.at(10);  // ❌ Throws std::out_of_range
    
    // ✅ Range-based for
    for (const auto& elem : arr) {
        std::cout << elem << " ";
    }
    
    // ✅ STL algorithms
    std::sort(arr.begin(), arr.end());
    auto it = std::find(arr.begin(), arr.end(), 3);
    
    // ✅ Can be copied/assigned
    std::array<int, 5> arr2 = arr;  // Copy!
    
    return 0;
}

std::array vs C-array

FeatureC-arraystd::array
Size known❌ Decays.size()
Bounds check❌ No.at()
Copyable❌ No✅ Yes
Assignable❌ No✅ Yes
Iterators❌ No✅ Yes
Pass by value❌ Decays✅ Works
Performance✅ Zero-cost✅ Zero-cost
Stack allocated✅ Yes✅ Yes

📌 Zero Overhead

std::arrayno runtime overhead so với C-array. Compiler optimizes it completely.


std::vector — Dynamic Array

Khi không biết size lúc compile-time:

cpp
#include <vector>
#include <iostream>

std::vector<int> readNumbers() {
    std::vector<int> nums;
    int n;
    
    while (std::cin >> n) {
        nums.push_back(n);  // ✅ Dynamic growth
    }
    
    return nums;  // ✅ Can return by value (move semantics)
}

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    // ✅ All array features plus:
    v.push_back(6);         // Dynamic add
    v.pop_back();           // Dynamic remove
    v.resize(10);           // Change size
    v.reserve(100);         // Pre-allocate
    
    // ✅ Range-based for
    for (const auto& elem : v) {
        std::cout << elem << " ";
    }
    
    return 0;
}

Khi nào dùng std::array vs std::vector?

Use CaseContainer
Size known at compile timestd::array
Size unknown/dynamicstd::vector
Performance-critical fixed-sizestd::array
Need to resizestd::vector
Stack allocation requiredstd::array
Very large datastd::vector (heap)

Migration Guide

Before (C-style)

cpp
// ❌ Old C-style
void processData(int data[], int size) {
    for (int i = 0; i < size; ++i) {
        data[i] *= 2;
    }
}

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    processData(arr, 5);  // Must pass size separately!
    
    return 0;
}

After (Modern C++)

cpp
// ✅ With std::array
void processData(std::array<int, 5>& data) {
    for (auto& elem : data) {
        elem *= 2;
    }
}

// ✅ Or generic with std::span (C++20)
void processData(std::span<int> data) {
    for (auto& elem : data) {
        elem *= 2;
    }
}

// ✅ Or with std::vector
void processData(std::vector<int>& data) {
    for (auto& elem : data) {
        elem *= 2;
    }
}

std::span — View into Contiguous Memory (C++20)

cpp
#include <span>
#include <vector>
#include <array>
#include <iostream>

// Works with ANY contiguous container!
void print(std::span<const int> data) {
    for (int x : data) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
}

int main() {
    int c_arr[] = {1, 2, 3};
    std::array<int, 3> std_arr = {4, 5, 6};
    std::vector<int> vec = {7, 8, 9};
    
    // All work!
    print(c_arr);     // 1 2 3
    print(std_arr);   // 4 5 6
    print(vec);       // 7 8 9
    
    // Subspan
    print(std::span(vec).subspan(1, 2));  // 8 9
    
    return 0;
}

2D Arrays

C-style (Avoid)

cpp
// ❌ Painful with functions
void process(int arr[][5], int rows) {
    // Second dimension must be compile-time constant!
}

Modern C++

cpp
// ✅ std::array of std::array (fixed)
std::array<std::array<int, 4>, 3> matrix = {{
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
}};

// ✅ std::vector of std::vector (dynamic)
std::vector<std::vector<int>> grid(3, std::vector<int>(4, 0));
grid[1][2] = 42;

// ✅ Flat std::vector (performance)
int rows = 3, cols = 4;
std::vector<int> flat(rows * cols);
flat[row * cols + col] = 42;  // Access [row][col]

HPN Standard Rules

📌 Array Guidelines

  1. Mặc định: Dùng std::vector
  2. Fixed size compile-time: Dùng std::array
  3. Never: Dùng raw C-arrays (trừ khi C interop)
  4. Prefer: Pass by const& hoặc std::span (C++20)
  5. Remember: std::array = stack, std::vector = heap

Performance Comparison

cpp
#include <array>
#include <vector>
#include <chrono>

// Both have O(1) random access
// std::array: Slightly faster initialization (no heap)
// std::vector: Slightly slower due to heap allocation

// In practice: Difference is negligible
// Choose based on requirements, not micro-optimization

📚 Tổng kết

ContainerUse When
C-array int[]❌ Never (legacy only)
std::array<T, N>Fixed size, compile-time known
std::vector<T>Dynamic size, default choice
std::span<T>View into any contiguous memory (C++20)

🎉 Hoàn thành Part 4: STL Containers!

Bạn đã nắm vững:

  • std::vector với size/capacity
  • std::string với SSO và operations
  • std::map / unordered_map
  • ✅ Big O analysis
  • ✅ Iterators và invalidation
  • ✅ Modern arrays

Tiếp theo: Part 5 — Modern C++ (Smart Pointers, Move Semantics, Lambdas)