开发者

Returning multidimensional array from function

How do I return a multidimensional array stored in a private field of my class?

class Myclass {
private:
   int myarray[5][5];
public:
   int **get_arra开发者_Python百科y();
};

// This does not work:
int **Myclass::get_array() {
    return myarray;
}

I get the following error:

cannot convert int (*)[5][5] to int** in return


A two-dimensional array does not decay to a pointer to pointer to ints. It decays to a pointer to arrays of ints - that is, only the first dimension decays to a pointer. The pointer does not point to int pointers, which when incremented advance by the size of a pointer, but to arrays of 5 integers.

class Myclass {
private:
    int myarray[5][5];
public:
    typedef int (*pointer_to_arrays)[5]; //typedefs can make things more readable with such awkward types

    pointer_to_arrays get_array() {return myarray;}
};

int main()
{
    Myclass o;
    int (*a)[5] = o.get_array();
    //or
    Myclass::pointer_to_arrays b = o.get_array();
}

A pointer to pointer (int**) is used when each subarray is allocated separately (that is, you originally have an array of pointers)

int* p[5];
for (int i = 0; i != 5; ++i) {
    p[i] = new int[5];
}

Here we have an array of five pointers, each pointing to the first item in a separate memory block, altogether 6 distinct memory blocks.

In a two-dimensional array you get a single contiguous block of memory:

int arr[5][5]; //a single block of 5 * 5 * sizeof(int) bytes

You should see that the memory layout of these things are completely different, and therefore these things cannot be returned and passed the same way.


There are two possible types that you can return to provide access to your internal array. The old C style would be returning int *[5], as the array will easily decay into a pointer to the first element, which is of type int[5].

int (*foo())[5] {
   static int array[5][5] = {};
   return array;
}

Now, you can also return a proper reference to the internal array, the simplest syntax would be through a typedef:

typedef int (&array5x5)[5][5];
array5x5 foo() {
   static int array[5][5] = {};
   return array;
}

Or a little more cumbersome without the typedef:

int (&foo())[5][5] {
   static int array[5][5] = {};
   return array;
}

The advantage of the C++ version is that the actual type is maintained, and that means that the actual size of the array is known at the callers side.


To return a pointer to your array of array member, the type needed is int (*)[5], not int **:

class Myclass {
private:
    int myarray[5][5];
public:
    int (*get_array())[5];
};

int (*Myclass::get_array())[5] {
    return myarray;
}


How do I return a multidimensional array hidden in a private field?

If it's supposed to be hidden, why are you returning it in the first place?

Anyway, you cannot return arrays from functions, but you can return a pointer to the first element. What is the first element of a 5x5 array of ints? An array of 5 ints, of course:

int (*get_grid())[5]
{
    return grid;
}

Alternatively, you could return the entire array by reference:

int (&get_grid())[5][5]
{
    return grid;
}

...welcome to C declarator syntax hell ;-)

May I suggest std::vector<std::vector<int> > or boost::multi_array<int, 2> instead?


Simpler would be decltype(auto) (since C++14)

decltype(auto) get_array() { return (myarray); } // Extra parents to return reference

then decltype (since C++11) (member should be declared before the method though)

auto get_array() -> decltype((this->myarray)) { return myarray; }
// or
auto get_array() -> decltype(this->myarray)& { return myarray; }

then typedef way:

using int2D = int[5][5]; // since C++11
// or
typedef int int2D[5][5];

int2D& get_array() { return myarray; }

as regular syntax is very ugly way:

int (&get_array())[5][5] { return myarray; }

Using std::array<std::array<int, 5>, 5> (since C++11) would have more natural syntax.


I managed to make this function work in C++0x using automatic type deduction. However, I can't make it work without that. Native C arrays are not supported very well in C++ - their syntax is exceedingly hideous. You should use a wrapper class.

template<typename T, int firstdim, int seconddim> class TwoDimensionalArray {
    T data[firstdim][seconddim];
public:
    T*& operator[](int index) {
        return data[index];
    }
    const T*& operator[](int index) const {
        return data[index];
    }
};
class Myclass {
public:
    typedef TwoDimensionalArray<int, 5, 5> arraytype;
private:
    arraytype myarray;
public:
    arraytype& get_array() {
        return myarray;
    }
};

int main(int argc, char **argv) {
    Myclass m;
    Myclass::arraytype& var = m.get_array();
    int& someint = var[0][0];
}

This code compiles just fine. You can get pre-written wrapper class inside Boost (boost::array) that supports the whole shebang.


Change your int's to int[][]'s or try using int[,] instead?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜