首先我们要知道c++是不能返回局部变量的引用或者局部变量的指针的,因为在函数调用结束之后这些局部变量都会变为空
vector<int> getVector() {
std::vector<int> vec = {1, 2, 3, 4, 5};
return vec;
}
但是我们这里确可以返回vector<int>数组,这是为什么呢?
其实vector
并不是一个数组,它更像是一个动态数组或变长数组。在 C++ 中,数组是一个连续的内存块,所有元素的类型相同,并且大小固定(即在创建时必须指定大小),而且数组的大小不能在运行时改变。
与之相反,std::vector
是一个由模板实现的容器,因此,我们通常将 std::vector
称为容器而不是数组。我们可以将 std::vector
看作是一个类,它封装了数据和一些操作这些数据的方法,这些方法包括添加、删除、查找等等。我们可以创建 std::vector
的对象(实例化)来存储数据。
在 C++ 中,返回类型为 vector<int>
的函数会返回一个副本(copy)而不是指针。当你将函数的返回类型指定为vector<int>
时,函数会创建一个新的 vector<int>
对象,并将其作为返回值拷贝到调用方。
所以:我们发现c++返回类型为vector<int>时,就和返回一个基本数据类型的变量是一个性质的,都是返回了变量的拷贝(返回一个结构体变量也是返回了拷贝)。
关于返回vector<int>的引用的讨论
当遇到返回vector<int>时,尤其是要返回的vector中的元素很多,还有一种方法是返回vector<int>的引用,但是我们知道不能返回局部变量的指针和引用,所以在这里必须要使用static来定义vector int
vector<int>& getVector() {
static std::vector<int> vec = {1, 2, 3, 4, 5};
return vec;
}
这样在函数调用结束后vector<int> vec就不用被释放空间,有人可能说vector不是数据存储在堆空间吗,为什么还会在函数调用释放呢?其实vector对象是定义在栈空间的,但是它的存储的数据是存储在堆空间的,在函数调用结束之后,这个对象会被释放,vector内部也有析构函数,在对象被释放后内存中的数据也会被析构函数释放,这个数据占用的堆空间和我们手动申请的堆空间不一样,手动申请的需要用delete来释放,但是这个vector对象被释放之后会自动将数据占用的内存也释放。
插一个题外话:我们使用new动态申请普通数组空间的时候其实也是分在两个位置进行的存储,指针变量存储在了栈空间,但是数据存储在了堆空间。
什么时候适合用返回vector对象的引用?
当我们返回vectorint数组的时候,我们其实返回了这个对象的拷贝,当vector向量占用的空间比较大的时候,拷贝花的时间还是很多的,这个时候我们就可以返回vector对象的引用,就不用拷贝这个对象了。但是话又说回来如果单纯为了这种情况的话,是不是定义一个全局的vector更方便呢?这样甚至不需要返回值了。看到了一篇文章说的是建议不要将vector的引用作为返回值(防止悬空引用即返回局部变量的引用),可以采用将vector的引用作为参数来传入。
什么时候不适合用返回vector对象的引用?
在那个ccf中的题目中,我们其实不适合使用返回vector的引用,因为不能返回局部变量的引用,要想返回变量引用,我们就得使用static,但是这个题目中使用了递归,这样的话static不会自动释放,递归时函数需要多次调用,但是这个vector对象就不能释放,所以不适合用引用作为返回值。
链接:CCF-CSP 29次 第三题【202303-3 LDAP】_第29次ccf csp认证题目java-CSDN博客
c++和JAVA的一点区别
c++中我们对于普通数组我们不能像返回vector对象一样返回拷贝,只能返回一个指针,所以c++中不能像返回vector一样返回数据的拷贝(返回普通变量和返回结构体变量,返回类的对象,其实一个vector对象也是类的对象这些返回原理差不多)一样,返回普通数组,但是在JAVA中数组也算得上是对象,因为JAVA中全都是对象,在JAVA中返回数组也相当于返回数组对象的拷贝,这样都一样了,这也算得上c++和JAVA区别,JAVA中能直接返回数组的拷贝