Chuyển tới nội dung chính

std::array

#include <array>

template <class T, size_t N> class array;

std::array trong C++ (được giới thiệu từ C++11) là một container tuần tự (sequence container) cung cấp mảng có kích thước cố định với các tính năng của thư viện chuẩn (STL). Nó tương tự như mảng C-style nhưng an toàn hơn và dễ sử dụng hơn.

Tham số

T

  • Kiểu dữ liệu của các phần tử trong array.

N

  • Kích thước của array (số lượng phần tử), phải là một hằng số nguyên xác định tại thời điểm biên dịch.

array

  • Tên của array bạn muốn tạo.

Đặc điểm

  1. Kích thước cố định: Kích thước của std::array được xác định tại thời điểm biên dịch và không thể thay đổi trong quá trình chạy.
  2. Truy cập ngẫu nhiên: Giống như mảng C-style, std::array cho phép truy cập ngẫu nhiên các phần tử thông qua toán tử [] hoặc hàm at() với độ phức tạp O(1).
  3. Lưu trữ liên tục: Các phần tử trong std::array được lưu trữ liên tục trong bộ nhớ, giống như mảng C-style.
  4. An toàn và hiệu quả hơn mảng tĩnh:
    • Cung cấp các hàm thành viên kiểm tra chỉ số như at() (ném ngoại lệ khi truy cập ngoài phạm vi).
    • Hỗ trợ các thao tác của container STL như begin(), end(), sort(), find(), copy(),...
  5. Tuân theo giao diện của STL container: Tích hợp tốt với các thuật toán trong STL (Standard Template Library).
  6. Hiệu năng tốt: Do lưu trữ các phần tử liên tiếp trong bộ nhớ, giống như mảng C thuần, std::array không có chi phí quản lý động như std::vector và có kích thước cố định giúp nó phù hợp với các ứng dụng yêu cầu hiệu năng cao.
  7. Không tự động quản lý bộ nhớ: std::array không tự động cấp phát lại bộ nhớ như std::vector. Kích thước của nó là cố định.
  8. Copy/Move: std::array hỗ trợ copy constructor và move constructor (C++11).
  9. Biết kích thước tại thời điểm biên dịch: Kích thước của std::array là một phần của kiểu dữ liệu, do đó nó được biết tại thời điểm biên dịch.
  10. Khi nào nên sử dụng std::array:
    • Khi bạn cần một mảng có kích thước cố định.
    • Khi bạn muốn tránh chi phí quản lý bộ nhớ động của std::vector.
    • Khi bạn cần sự an toàn và tiện lợi hơn so với mảng C-style.
    • Khi bạn muốn sử dụng các tính năng của thư viện chuẩn STL cho mảng.

Ví dụ:

#include <iostream>
#include <array>

int main() {
// Khai báo mảng
std::array<int, 5> arr = {1, 2, 3, 4, 5};

// Truy cập phần tử
std::cout << "Element at index 2: " << arr.at(2) << "\n";

// Duyệt qua mảng
std::cout << "Array elements: ";
for (int x : arr) {
std::cout << x << " ";
}
std::cout << "\n";

// Hoán đổi và gán giá trị
std::array<int, 5> arr2;
arr2.fill(10);
arr.swap(arr2);

// In sau khi hoán đổi
std::cout << "Array after swap: ";
for (int x : arr) {
std::cout << x << " ";
}

return 0;
}

Các cách phổ biến khai báo và khởi tạo một std::array

  1. Khai báo mảng không khởi tạo giá trị:

    Khi không cung cấp giá trị khởi tạo, các phần tử trong std::array sẽ được khởi tạo mặc định (với kiểu dữ liệu nguyên thủy thì thường là 0, còn với kiểu không nguyên thủy thì constructor mặc định sẽ được gọi).

    // Mảng có kích thước 5, các phần tử được khởi tạo mặc định (0).
    std::array<int, 5> arr;
  2. Khởi tạo bằng danh sách khởi tạo (Initializer List):

    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    Lưu ý
    • Nếu số phần tử cung cấp ít hơn kích thước Size, các phần tử còn lại sẽ được khởi tạo mặc định.
    • Nếu số phần tử nhiều hơn Size, trình biên dịch sẽ báo lỗi.
  3. Khởi tạo tất cả phần tử bằng một giá trị:

    Sử dụng phương thức fill() để gán tất cả phần tử bằng cùng một giá trị sau khi khai báo.

    std::array<int, 5> arr;
    arr.fill(42); // Gán tất cả các phần tử bằng 42.
  4. Khởi tạo bằng cách sao chép một std::array khác:

    std::array<int, 3> arr1 = {1, 2, 3};
    std::array<int, 3> arr2 = arr1; // Sao chép arr1 sang arr2.
  5. Khởi tạo với kiểu dữ liệu phức tạp:

    Bạn có thể sử dụng std::array với bất kỳ kiểu dữ liệu phức tạp nào như struct, class, hoặc con trỏ.

    struct Point {
    int x, y;
    };

    std::array<Point, 2> points = {{{1, 2}, {3, 4}}};
  6. Sử dụng constexpr với std::array (C++17 trở lên):

    std::array có thể được khai báo và khởi tạo trong constexpr để sử dụng trong các biểu thức hằng số.

    constexpr std::array<int, 3> arr = {1, 2, 3};

Các kiểu dữ liệu đặc biệt của std::array

lưu ý

Giống như std::vector, std::array cũng là container tổng quát (generic containers) được thiết kế để lưu trữ bất kỳ kiểu dữ liệu hợp lệ nào trong C++ mà bạn có thể định nghĩa ngoài int, float, double,... như struct, class, con trỏ, con trỏ thông minh, container lồng nhau, enum, tuplepair.

  1. Structs (Cấu trúc):

    struct Point {
    int x, y;
    };

    std::array<Point, 3> points = {{{1, 2}, {3, 4}, {5, 6}}};
  2. Classes (Lớp):

    class Rectangle {
    public:
    int width, height;
    Rectangle(int w, int h) : width(w), height(h) {}
    int area() const { return width * height; }
    };

    std::array<Rectangle, 2> rects = {Rectangle(3, 4), Rectangle(5, 6)};
  3. Pointers và Smart Pointers:

    #include <array>
    #include <memory>
    #include <iostream>

    int main() {
    // std::array chứa con trỏ thô
    std::array<int*, 3> ptrArray = {new int(10), new int(20), new int(30)};
    for (const auto& ptr : ptrArray) {
    std::cout << *ptr << " ";
    delete ptr; // Giải phóng bộ nhớ
    }

    std::cout << "\n";

    // std::array chứa con trỏ thông minh
    std::array<std::shared_ptr<int>, 3> smartPtrArray = {
    std::make_shared<int>(40), std::make_shared<int>(50), std::make_shared<int>(60)};
    for (const auto& smartPtr : smartPtrArray) {
    std::cout << *smartPtr << " ";
    }

    return 0;
    }
  4. Containers lồng nhau (Nested Containers):

    std::array<std::vector<int>, 2> nestedContainers = {{{1, 2, 3}, {4, 5, 6}}};
  5. Enums (Kiểu liệt kê):

    enum class Color { Red, Green, Blue };
    std::array<Color, 3> colors = {Color::Red, Color::Green, Color::Blue};
  6. Tuples và Pairs:

    #include <array>
    #include <tuple>
    #include <iostream>

    int main() {
    std::array<std::pair<int, std::string>, 2> pairArray = {
    std::make_pair(1, "One"), std::make_pair(2, "Two")};
    for (const auto& pair : pairArray) {
    std::cout << pair.first << " - " << pair.second << "\n";
    }

    std::array<std::tuple<int, double, std::string>, 2> tupleArray = {
    std::make_tuple(1, 1.1, "One"), std::make_tuple(2, 2.2, "Two")};
    for (const auto& tuple : tupleArray) {
    std::cout << std::get<0>(tuple) << ", " << std::get<1>(tuple) << ", "
    << std::get<2>(tuple) << "\n";
    }

    return 0;
    }

Các hàm thành viên

Trình lặp (Iterators)

beginTrả về một iterator trỏ đến phần tử đầu tiên của std::array
endTrả về một iterator trỏ đến vị trí ngay sau phần tử cuối cùng của std::array
rbeginTrả về một iterator ngược trỏ đến phần tử cuối cùng của std::array
rendTrả về một iterator ngược trỏ tới phần tử trước phần tử đầu tiên của std::array
cbeginTrả về một iterator hằng trỏ tới phần tử đầu tiên của std::array
cendTrả về một iterator hằng trỏ tới phần tử ngay sau phần tử cuối cùng của std::array
crbeginTrả về một iterator ngược hằng (constant reverse iterator) trỏ tới phần tử cuối cùng của std::array
crendTrả về một iterator ngược hằng trỏ tới phần tử trước phần tử đầu tiên của std::array

Dung lượng (Capacity)

sizeTrả về số lượng phần tử hiện có trong std::array
max_sizeTrả về số lượng phần tử tối đa mà std::array có thể chứa
emptyKiểm tra xem một mảng std::array có rỗng hay không

Truy cập phần tử

[]Truy xuất phần tử tại vị trí chỉ định
atTruy xuất phần tử tại vị trí chỉ định
frontTruy xuất phần tử tại vị trí đầu tiên
backTruy xuất phần tử tại vị trí cuối cùng
dataTrả về con trỏ trỏ tới phần tử đầu tiên của vùng lưu trữ bên trong mảng std::array

Thay đổi nội dung (Modifiers)

fillGán một giá trị cụ thể cho tất cả các phần tử trong mảng std::array
swapHoán đổi nội dung của hai mảng std::array

Toán tử quan hệCác toán tử quan hệ trong std::array