为什么我们不应该使用在类中返回数组或指针的函数呢
Why should not we use a function that returns an array or pointer in a class
我的问题是,如果函数返回数组,会出现什么问题?我们可以使用这样的功能吗?
C++不允许函数将数组类型作为prvalue返回;xvalues和lvalues很好,不过:
using T = int[10];
T & foo(); // OK, returns lvalue
T && foo(); // OK, returns xvalue
T foo(); // Error, not allowed
函数类型也是如此(尽管在这种情况下,函数调用表达式的结果总是一个左值)。参见[dcl.fct]/10:
函数不应具有类型为数组或函数的返回类型,尽管它们可能具有类型为指针或引用的返回类型。
类似地,数组和函数类型不能是函数参数类型(但对它们的引用可以),但具有此类类型的函数参数的声明含义被调整为"指向{数组元素类型,函数类型}的指针"。
C++和C函数中都不能有数组的返回类型。数组没有复制构造函数或复制赋值运算符。
然而,在C++中,您可以返回对数组的引用。
考虑以下示例
#include <iostream>
#include <numeric>
const size_t N = 10;
int ( & init( int ( &a )[N], int initial ) )[N]
{
std::iota( a, a + N, initial );
return a;
}
std::ostream & print( const int ( &a )[N], std::ostream &os = std::cout )
{
for ( int x : a ) os << x << ' ';
return os;
}
int main()
{
int a[N];
print( init( a, 0 ) ) << std::endl;
print( init( a, 10 ) ) << std::endl;
return 0;
}
输出为
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
但是,您可能不会返回对函数的本地数组的引用或指针(指向第一个元素)。在这种情况下,程序将具有未定义的行为。
但是您可以使用数组std::array
的标准包装器,并从函数返回它。
以下是的示例
#include <iostream>
#include <numeric>
#include <array>
const size_t N = 10;
std::array<int, N> init(int initial = 0 )
{
std::array<int, N> a;
std::iota( a.begin(), a.end(), initial );
return a;
}
std::ostream & print( const std::array<int, N> &a, std::ostream &os = std::cout )
{
for ( int x : a ) os << x << ' ';
return os;
}
int main()
{
std::array<int, N> a;
a = init();
print( a ) << std::endl;
a = init( 10 );
print( a ) << std::endl;
return 0;
}
程序输出与上述相同
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
正如Mike Seymour所说,函数不能返回数组,只能返回指向其第一个元素的指针。
它本身是完全正确的,但如果误用,可能会导致错误。可能出现的一些问题:
-
返回一个指向自动数组的指针:当您尝试访问时,一旦函数返回=>UB,if就会被销毁
int * arr() { int arr[10]; // automatic array ... return arr; // WRONG ! UB when accessed from caller ... }
-
返回一个指向动态分配的数组的指针:很好,但调用方必须在它不再使用时释放它,否则将出现内存泄漏
int * arr() { int *arr = new int[10]; // automatic array ... return arr; MUST be freed by caller ... } for (int i=0; i<5, i++) { int *a = arr(); ... // use a } // no delete[] a in loop => memory leak !
-
返回指向静态数组的指针:很好,但不应在多线程上下文中使用
int * arr() { static int arr[10]; // automatic array ... return arr; // as arr is static it will persist after function returns }
线程a:
int *a = arr();
线程b:
int *a = arr();
现在,两个线程都通过其
a
指针共享同一个数组,如果数组不是只读的,则通常不会出现。
正如我所说,可以将指针返回到非自动数组。它必须谨慎使用,因为它经常会导致问题。
停止使用这些旧东西。开始使用STL。您可以始终将vector or string
传递到function parameters
中,并始终从函数中获得两者作为return
值。
它可以返回一个指向数组开头的指针。如果函数返回后数组继续存在,这是可以的。但是,如果数组是一个局部自动变量,就会出现严重的错误,因为当函数返回时,它会被破坏,留下指针。尝试访问数组的剩余部分会产生未定义的行为。
既然你问了一个例子:
int * bogus() {
int array[] = {1,2,3,4,5};
return array; // Whoops! array is destroyed here
}
int * p = bogus();
assert(p[2] == 3); // BOOM! undefined behaviour
如果数组的大小很小,可以将其封装在类中以返回其副本;标准库为此提供CCD_ 6。
如果您需要动态分配数组(因为它很大,或者只有在运行时才知道大小),那么std::vector
就是您的朋友。
- 添加到数组指针
- C++语法差异:二维和一维数组(指针算术)
- 数组指针表示法C++(移动数组时)
- 复制后删除原始数组指针将前 3 个字节设置为 0
- C++访问指向结构的指针中的类数组指针
- C++编译时使用 constexpr 字符数组指针分配静态数组?
- std::flush可以用于将对象指针转换为其封闭数组指针吗
- 创建<int>对整数数组指针的矢量引用 (C++)
- 将 2D 数组指针传递给 C++ 中的函数
- 创建指针是否超过非数组指针的末尾,而不是从 C++17 中的一元运算符和未定义的行为派生?
- 队列数组指针 (C++)
- C++数组指针上的删除操作
- 对于循环不循环和检测字符数组 [指针和字符数组]
- 如何初始化数组指针对象
- 如何正确传递 2D 数组指针作为参数
- 从数组指针中获取怪异的数字
- 初始化std :: unique_ptr作为原始数组指针的初始化
- 将结构数组指针从C#传递到C
- STD :: Sort将数组指针设置为NULL
- C++数组指针错误无法将“int*”转换为“int**”