在 C++ 中,std::vector 是一种动态数组容器,它可以在运行时动态地分配和管理内存。std::vector 存储的元素通常是连续分配的,并且可以根据需要动态地调整其大小。因此,std::vector 中的元素存储在堆区内存。
当我们创建一个 std::vector 对象时,它会在堆区分配一段连续的内存空间,用于存储其元素。这段内存空间的大小取决于 std::vector 对象的大小和元素数量。在向 std::vector 中添加元素时,如果当前的内存空间不足以容纳新元素,std::vector 会自动分配更大的内存空间,将原有的元素拷贝到新的内存空间中,并释放原有的内存空间。(可能会有 迭代器失效的问题)
需要注意的是,std::vector 对象本身可以存储在栈区或堆区。如果我们使用 new 运算符动态分配一个 std::vector 对象,它将存储在堆区。例如:
std::vector<int>* vec = new std::vector<int>(); // 存储在堆区
// 如果我们将 std::vector 对象定义为一个局部变量或全局变量,则它将存储在栈区。例如:
void foo(){
std::vector<int> vec; // 存储在栈区
}
std::vector<int> global_vec; // 存储在栈区
无论 std::vector 存储在栈区还是堆区,其元素始终存储在堆区内存中。因此,我们可以将 std::vector 作为参数传递给函数,而不会担心复制大量数据的性能问题。
这个有点类似与智能指针,智能指针对象本身是可以存在在栈区或者堆区的,用于管理动态分配的内存,因此它需要存储在堆区。
std::shared_ptr 对象本身可以存在于堆区或栈区,这取决于它是如何创建的。
如果我们使用 new 运算符来创建一个 std::shared_ptr 对象,它将存储在堆区。例如:
std::shared_ptr<int>* ptr = new std::shared_ptr<int>(newint(42)); // ptr 存在于堆区,指向的内存块也存在于堆区
在这个例子中,ptr 存储在堆区,它指向的内存块也存储在堆区。
如果我们将 std::shared_ptr 对象定义为一个局部变量或全局变量,它将存储在栈区。例如:
void foo(){
std::shared_ptr<int> ptr(newint(42)); // ptr 存在于栈区,指向的内存块存在于堆区
}
std::shared_ptr<int> global_ptr(newint(42)); // global_ptr 存在于栈区,指向的内存块存在于堆区
在这个例子中,ptr 和 global_ptr 存储在栈区,它们指向的内存块存储在堆区。
需要注意的是,无论 std::shared_ptr 存储在堆区还是栈区,它所指向的内存块始终存储在堆区。这是因为 std::shared_ptr 是用于管理动态分配的内存的智能指针,它需要存储在堆区,以便进行引用计数和自动释放内存。
而且引用计数也是存放在堆区的,使用make_shared去创建智能指针的时候,引用计数位于分配的对象前面4B的位置。
当我们使用 std::make_shared 创建一个智能指针对象时,内存分配和对象构造都是在同一块连续的内存中完成的。这种内存布局称为“控制块”,它存储了引用计数、指向堆区内存的指针以及其他辅助信息。因此,通过 std::make_shared 创建的对象是一个连续的内存块,其中智能指针对象本身存储在控制块中。
void foo(){
auto ptr = std::make_shared<int>(42); // ptr 存在于栈区,指向的内存块存在于堆区
}
std::shared_ptr<int> global_ptr = std::make_shared<int>(42); // global_ptr 存在于栈区,指向的内存块存在于堆区
在这个例子中,ptr 和 global_ptr 存储在栈区,它们指向的内存块存储在堆区。
需要注意的是,无论 std::shared_ptr 存储在堆区还是栈区,它所指向的内存块始终存储在堆区。这是因为 std::shared_ptr 是用于管理动态分配的内存的智能指针,它需要存储在堆区,以便进行引用计数和自动释放内存。所以 std::make_shared 函数返回的 std::shared_ptr 对象实际上是一个包含了指向堆区内存的智能指针对象。
总的来说,其实我们使用智能指针就是想用一个栈对象去托管资源,这样当栈对象被自动析构的时候就会去释放它所托管的资源,这部分大家可以参考RAII智能指针雏形。
如果有帮到你,就点个赞吧~