为什么我们不应该使用在类中返回数组或指针的函数

时间:2015-04-02 11:44:19

标签: c++ class pointers

我的问题是如果函数返回一个数组可能会出错?我们可以使用这样的功能吗?

5 个答案:

答案 0 :(得分:1)

C ++不允许函数将数组类型作为prvalue返回;但是,xvalues和左值很好:

using T = int[10];

T  & foo();    // OK, returns lvalue
T && foo();    // OK, returns xvalue
T    foo();    // Error, not allowed

同样是函数类型(尽管在这种情况下函数调用表达式的结果总是左值)。见[dcl.fct] / 10:

  

函数不应具有类型数组或函数的返回类型,尽管它们可能具有类型指针的返回类型或对此类事物的引用。

类似地,数组和函数类型不能是函数参数类型(但是对它们的引用可以),但是具有这种类型的函数参数声明的含义被调整为"指向{数组元素类型,函数类型的指针}"

答案 1 :(得分:1)

在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 

答案 2 :(得分:0)

函数不能直接返回数组,因为不能简单地复制或移动数组。

它可以返回指向数组开头的指针。如果函数返回后数组继续存在,这很好。但是如果数组是一个局部自动变量,那将会出现可怕的错误,因为它会在函数返回时被销毁,而指针会悬空。试图访问数组的残余将给出未定义的行为。

因为你问了一个例子:

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

如果数组有一个小的固定大小,你可以将它包装在一个类中以返回它的副本;标准库为此提供了std::array

如果你需要动态分配数组(因为它很大,或者只在运行时知道大小),那么std::vector就是你的朋友。

答案 3 :(得分:0)

停止使用这些旧东西。开始使用 STL 。您始终可以将vector or string传递到function parameters,并始终将其作为return值从函数中获取。

答案 4 :(得分:0)

正如Mike Seymour所说,函数不能返回一个数组,只能指向它的第一个元素。

本身完全正确,但如果误用可能会导致错误。可能出现的一些问题:

  • 返回一个指向自动数组的指针:如果函数返回= if将被销毁UB当您尝试访问它时

    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指针共享相同的数组,如果数组不是只读的话,通常不期望

正如我所说,返回指向非自动数组的指针是可以的。必须谨慎使用它,因为这通常会导致问题。