vector空间配置和栈空间返回引用的困惑和解答
STL二级空间配置器
简单介绍一下C++STL中空间配置器的设计:
STL空间配置器分为两级,一级是直接调用系统的C函数malloc来从heap空间申请内存,二级是通过STL内部维护的内存池来分配内存。
具体使用哪个配置器,是通过一个阈值来判断,默认的为128Bytes;大于128字节时,调用一级配置器;小于则使用二级配置器。
这样做的最大好处就是防止内存碎片化(分为内部碎片和外部碎片,详见CSAPP的虚拟内存章节),而且每次使用malloc从堆中申请内存时,都需要在头部存放
内存的链表信息,实际申请的内存比调用malloc时需要的其实更大一点,所以过多小额内存会使堆空间的有效利用率降低(同TCP/IP的有效载荷一个性质,基本的IP头和TCP头就占用了40个字节)。
vector内存配置器
STL容器都是默认使用STL定义的二级空间配置器,但C++也允许用户自行设计一个更适合应用场景的配置器来替换。
但大多数情况下,默认的二级空间配置器满足使用的要求。
这里我的疑问是,既然vector使用的是二级空间配置器,那么容器中的数据都是存放在了堆空间。如果在栈空间声明了vector,向其中添加了一个数据,能否返回其引用,
该引用保留了这个数据。
显然,这个问题答案是不可能的,具体还是实验一下。
#include <iostream>
#include <vector>
using namespace std;
vector<int>& func(){
vector<int> vec{1};
return vec;
}
int main(){
vector<int> vec = func();
for(auto i: vec)
cout << i << " ";
cout << endl;
}
编译时编译器就会提出警告warning: reference to local variable 'vec' returned
,运行后直接报错segmentation fault (core dumped)
,显然内存访问错误。
显然,在栈空间初始化的变量离开作用域的栈空间时,会默认调用析构函数,将vector的空间释放(包括vector内部定义的start, finish和end_of_storage来指示内部空间
的变量都会被析构,容器占用的空间归还给堆空间),所以遵守了C++的约定,定义在栈空间的数据不能在栈空间外访问,及时能访问也是不正确的,因为此栈空间随时可能
被后面的函数调用覆盖,另作他用。
测试栈空间自动调用析构函数
#include <iostream>
using namespace std;
struct TestCase{
TestCase(){cout << "Constructor Called" << endl;};
~TestCase(){cout << "Deconstructor Called"<< endl;};
};
TestCase& test(){
TestCase t;
return t;
}
int main(){
TestCase t = test();
}
编译运行结果是:
Constructor Called
Deconstructor Called
验证了想法。