【C++之STL】001序列容器篇vector的优缺点以及构造和析构函数


C++中的std::vector是一个动态数组,它提供了在运行时改变大小的能力。std::vector是C++标准库的一部分,位于头文件中。

介绍

std::vector是一个模板类,可以存储任何类型的对象,只要该类型定义了拷贝构造函数和赋值操作符。std::vector内部使用连续的内存来存储元素,这意味着可以通过索引快速访问任何元素,就像使用普通数组一样。

优点

  • 动态大小:std::vector的大小可以在运行时改变,这使得它非常适合存储大小未知的数据集。
  • 连续内存:由于std::vector使用连续的内存来存储元素,因此可以通过索引快速访问任何元素。此外,这也使得std::vector能够高效地与C风格的数组和指针一起使用。
  • 自动内存管理:std::vector负责其内部元素的内存分配和释放,因此不需要手动管理内存。这减少了内存泄漏和错误的可能性。
  • 支持迭代器:std::vector支持迭代器,这使得它可以与STL算法一起使用,从而简化了代码并提高了效率。
  • 多种成员函数:std::vector提供了许多有用的成员函数,如push_back、pop_back、resize、erase等,使得操作更加简单方便。

缺点

  • 空间效率:由于std::vector使用连续的内存来存储元素,当需要增加大小时,可能需要重新分配内存并将现有元素复制到新的内存位置。这可能导致一些性能开销。
  • 插入和删除的效率:在std::vector的中间位置插入或删除元素可能需要移动大量的元素,因为需要保持内存的连续性。这可能导致较高的时间复杂度(O(n))。
  • 初始大小:虽然std::vector可以动态调整大小,但如果初始大小设置不当,可能会导致频繁的内存重新分配和元素复制,从而影响性能。

总的来说,std::vector是一个强大而灵活的工具,适用于许多应用场景。了解其优点和缺点有助于更好地选择合适的数据结构来解决问题。

构造函数

std::vector 是 C++ 标准库中的一个非常灵活的动态数组类模板,它提供了多种构造函数来初始化向量。以下是一些常用的 std::vector 构造函数及其描述:

默认构造函数

vector<T> v;

这个构造函数创建一个空的 vector,不包含任何元素。

带有大小和初始值的构造函数

vector<T> v(n);
vector<T> v(n, value);

这些构造函数创建一个包含 n 个元素的 vector。如果提供了 value,则所有元素都将初始化为该值;否则,对于类类型的元素,将调用其默认构造函数进行初始化。

复制构造函数

vector<T> v(const vector<T>& other);

这个构造函数创建一个与 other 向量具有相同大小和内容的副本。

移动构造函数(C++11 及以后版本)

vector<T> v(vector<T>&& other) noexcept;

这个构造函数通过移动 other 向量的资源来创建一个新的向量,other 向量在移动后将处于有效但未定义的状态。

迭代器构造函数

template <class InputIterator>
vector<T> v(InputIterator first, InputIterator last);

这个模板构造函数接受两个迭代器参数,first 和 last,它们定义了一个输入范围。新创建的 vector 将包含从 first 到 last(不包括 last)范围内的所有元素。

初始化列表构造函数(C++11 及以后版本)

vector<T> v = {a, b, c, ...};

这个构造函数使用初始化列表来创建 vector,其中 a, b, c, … 是要添加到 vector 中的初始值。

列表初始化构造函数(C++11 及以后版本)

vector<T> v{a, b, c, ...};

这与上面的初始化列表构造函数类似,但它使用花括号 {} 而不是等号 = 进行初始化。

以下是一个简单的示例,展示了如何使用 std::vector 的不同构造函数:

#include <vector>
#include <iostream>

int main() {
    // 默认构造函数
    std::vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);

    // 带有大小和初始值的构造函数
    std::vector<int> v2(5);         // 含有5个默认初始化的int(值为0)
    std::vector<int> v3(5, 3);      // 含有5个值为3的int

    // 复制构造函数
    std::vector<int> v4(v1);

    // 初始化列表构造函数
    std::vector<int> v5 = {10, 20, 30};

    // 列表初始化构造函数
    std::vector<int> v6{40, 50, 60};

    // 输出向量的内容
    for (const auto& elem : v1) {
        std::cout << elem << " ";
    }
    std::cout << "\n";

    for (const auto& elem : v5) {
        std::cout << elem << " ";
    }
    std::cout << "\n";

    return 0;
}

在这个示例中,我们创建了几个 std::vector 实例,并使用了不同的构造函数来初始化它们。然后,我们遍历并打印出两个向量的内容。

析构函数

std::vector 的析构函数是自动调用的,当你不再需要一个 vector 对象时,它的析构函数就会被调用。std::vector 的析构函数负责释放向量所占用的内存,包括动态分配的元素数组以及任何可能由向量拥有的其他资源。

std::vector 的析构函数是自动调用的,你通常不需要显式调用它。它会在以下情况被调用:

  • 当 vector 对象离开其作用域时。
  • 当 vector 对象被销毁时,例如通过 delete 操作符删除一个指向 vector 的指针。
  • 当 vector 是另一个类的成员,并且那个类的对象被销毁时。

std::vector 的析构函数会执行以下操作:

  • 释放向量中存储的所有元素。如果元素是动态分配的(例如,指向其他动态对象的指针),这些元素本身不会被删除,因为它们可能由 vector 的所有者负责管理。
  • 释放用于存储元素的动态分配的数组。
  • 如果向量拥有任何其他资源(这通常不是 std::vector 的标准行为,但可能是通过自定义分配器或其他方式实现的),则这些资源也会被释放。

析构函数没有返回值,并且不能显式调用。它的主要目的是确保资源得到适当的清理,以防止内存泄漏和其他资源泄露问题。

下面是一个简单的例子,展示了 std::vector 析构函数的自动调用:

#include <vector>
#include <iostream>

int main() {
    {
        // 在这个作用域内创建一个 vector 对象
        std::vector<int> v;
        v.push_back(1);
        v.push_back(2);
        v.push_back(3);

        // 当这个作用域结束时,v 的析构函数会被自动调用
    } // v 的析构函数在这里被调用,释放内存和其他资源

    // v 不再存在,尝试访问它会导致未定义行为

    return 0;
}

在这个例子中,当 v 离开其作用域时,它的析构函数会自动被调用,释放它所占用的内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊猫Devin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值