首先明确一点:c++代码中无法直接返回数组,这一点比较清晰简单,我们写个方法进行测试
int* f1(int a[3], int b[3]) {
int c[3];
c[0] = a[0]*b[0];
c[1] = a[1]*b[1];
c[2] = a[2]*b[2];
return c;
}
int main(int argc, char const *argv[])
{
int a[] = {1, 2, 3};
int b[] = {4, 5, 6};
int *c = f1(a, b);
cout<
上面代码运行得到的结果为
point_array.cc:21:12: warning: address of stack memory associated with local variable 'c' returned [-Wreturn-stack-address]
return c;
^
1 warning generated.
4 37105316 1
原因也很容易解释:
我们在f1内定义的数组c,在f1执行完毕以后被系统释放掉,所以在调用f1方法得到的结果肯定就不是计算以后得到的正确结果。
为了解决上面的问题,我们可以在函数内new一个数组出来,这样new出来的数组被分配在堆空间上,函数执行完毕不会被释放。
int* f2(int a[3], int b[3]) {
int *c = new int[3];
c[0] = a[0]*b[0];
c[1] = a[1]*b[1];
c[2] = a[2]*b[2];
return c;
}
int main(int argc, char const *argv[])
{
int a[] = {1, 2, 3};
int b[] = {4, 5, 6};
int *c = f2(a, b);
cout<
上面代码运行
4 10 18
因为上面的数组是在函数内new出来,而在调用以外释放,逻辑不是特别清晰,因此可以改为下面的方式
void f3(int a[3], int b[3], int c[3]) {
c[0] = a[0]*b[0];
c[1] = a[1]*b[1];
c[2] = a[2]*b[2];
}
int main(int argc, char const *argv[])
{
int a[] = {1, 2, 3};
int b[] = {4, 5, 6};
int *c = new int[3];
f3(a, b ,c);
cout<
因为c++中手动分配内存的一个标准就是谁分配谁释放,因此,我们最好的方式是在函数外new分配内存,并在函数外释放。
上面使用指针的方式返回数组,需要手动进行内存管理。如果没有进行内存释放,或者没有在合适的位置释放内存,都会带来内存泄漏的问题。因此从c++11以后,引用了智能指针,可以方便我们进行各种操作而不是担心内存管理问题。
unique_ptr f4(int a[3], int b[3]) {
unique_ptr unique(new int[3]);
unique[0] = a[0] * b[0];
unique[1] = a[1] * b[1];
unique[2] = a[2] * b[2];
return unique;
}
int main(int argc, char const *argv[])
{
int a[] = {1, 2, 3};
int b[] = {4, 5, 6};
auto unique = f4(a, b);
cout<
上面的例子是使用unique_ptr返回一个数组。可以看到还是相当方便,相比于后面介绍的shared_ptr,unique_ptr的使用更为方便,因为他重载了下标运算符,我们可以把他直接像普通数组一样使用。
相比unique_ptr,平时使用得更多的是shared_ptr。先看例子。
shared_ptr f5(int a[3], int b[3]) {
shared_ptr ptr(new int[3], [](int *p) {delete[] p;});
auto p = ptr.get();
p[0] = a[0] * b[0];
p[1] = a[1] * b[1];
p[2] = a[2] * b[2];
return ptr;
}
int main(int argc, char const *argv[])
{
int a[] = {1, 2, 3};
int b[] = {4, 5, 6};
auto ptr = f5(a, b);
int *p = ptr.get();
cout<
代码输出结果
4 10 18
在c++11中,shared_ptr严格意义上来说是不支持动态数组的,比如我们如下的声明是错误的,因为shared_ptr中的模板参数不能是int[]
shared_ptr ptr2(new int[3], [](int *p) {delete[] p;});
下面的方式也是有问题的
shared_ptr ptr2(new int[3]);
因为shared_ptr对非数组类型都使用delete p释放资源,而new int[3]不能直接用delete释放,需要用delete []。
最后的使用方法就是我们上面正确运行方法中的那一句
shared_ptr ptr(new int[3], [](int *p) {delete[] p;});
模板参数为int类型,同时用一个lambda函数指定delete方式即可。
同时在c++11中,shared_ptr未重载下标运算符,所以我们赋值取值等操作,需要先试用get()方法得到"原始"指针再进行操作。
在后续的c++版本中,shared_ptr针对数组操作有所改进与简化。从第4部分,我们不难看出c++11中用shared_ptr管理动态数组的缺点:
1.数组的形式是int[],而声明初始化的时候我们使用的shared_ptr
类型。
2.需要我们手动提供delete方法。
3.未提供下标操作,当需要使用类似下标操作时候比较繁琐。
4.无法使用make_shared方法,无法在异常的时候保证安全。
在c++17上,shared_ptr支持了上面的1,2,3点,可以使用下标进行操作,并且使用int[]做为模板操作。
#include
#include
int main()
{
std::shared_ptr sp(new int[3]());
for (int i = 0; i < 5; ++i) {
sp[i] = i+1;
}
for (int i = 0; i < 3; ++i) {
std::cout << sp[i] << std::endl;
}
}
可以看出来,上面的操作就跟直接操作数组比较类似了
在c++20中,对第4点做出了支持。
auto up2 = std::make_unique(10); // 从c++14开始,分配一个管理有10个int元素的动态数组的unique_ptr
// c++2a中你可以这样写,与上一句相似,只不过返回的是shared_ptr
auto sp3 = std::make_shared(10);
https://www.cnblogs.com/apocelipes/p/10346928.html