简体   繁体   中英

Why should not we use a function that returns an array or pointer in a class

My question is what may go wrong if a function returns an array? Can we use such function?

C++ does not allow a function to return an array type as a prvalue; xvalues and lvalues are fine, though:

using T = int[10];

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

The same is function types (although in that case the result of the function call expression is always an lvalue). See [dcl.fct]/10:

Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things.

Similarly, array and function types cannot be function parameter types (but references to them can), but the meaning of declaration of a function parameter with such type is adjusted to "pointer to {array element type, function type}".

Neither in C++ nor in C functions may have return type of an array. Arrays do not have a copy constructor or the copy assignment operator.

Nevertheless in C++ you may return a reference to an array.

Consider the following example

#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;
}

The output is

0 1 2 3 4 5 6 7 8 9 
10 11 12 13 14 15 16 17 18 19 

However you may not return reference to or pointer (to the first element) to a local array of a function. In this case the program will have undefined behaviour.

But you can use standard wrapper for arrays std::array and return it from functions.

Here is an example

#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;
}

The program output is the same as above

0 1 2 3 4 5 6 7 8 9 
10 11 12 13 14 15 16 17 18 19 

A function can't directly return an array, since arrays can't be simply copied or moved.

It could return a pointer to the start of an array. This is fine if the array continues to exist once the function has returned. But it will go horribly wrong if the array is a local automatic variable, since it will be destroyed when the function returns, leaving the pointer dangling. Trying to access the remnants of the array will give undefined behaviour.

Since you asked for an example:

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

If the array has a small, fixed size, you could wrap it in a class to return a copy of it; the standard library provides std::array for this.

If you need the array to be dynamically allocated (because it's large, or the size is only known at runtime), then std::vector is your friend.

stop using this old things. start working with . you can always pass vector or string into the function parameters and always get that both as return value from function.

As already said by Mike Seymour, a function cannot return an array but just a pointer to its first element.

It is perfectly correct per se, but can lead to errors if misused. Some problems that could arise :

  • return a pointer to an automatic array : if will be destroyed as soon as the function returns => UB when you try to access to it

     int * arr() { int arr[10]; // automatic array ... return arr; // WRONG ! UB when accessed from caller ... } 
  • return a pointer to a dynamically allocated array : fine but caller must free it when it is no longer used or you will have a memory leak

     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 ! 
  • return a pointer to a static array : fine but it should not be used in a multi threaded context

     int * arr() { static int arr[10]; // automatic array ... return arr; // as arr is static it will persist after function returns } 

    Thread a :

     int *a = arr(); 

    Thread b :

     int *a = arr(); 

    Both thread are now sharing the same array through their a pointer, what is generally not expected if array is not read only.

As I said, it can be fine to return a pointer to a not automatic array. It must simply be used with caution because is often leads to problems.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM