Thomas Kejser
Thomas Kejser

Reputation: 1294

What is the best way to return reference to a constant sized array of pointers?

I have an array of pointers declared as a class member like this:

class Bar
{
private:
  static constexpr int SIZE = 10;    
  Foo* m[SIZE];
}

In one of my class methods, I would like to return a pointer (or preferably, a reference) to this array. The array has a known size at compile time, but I am keeping track of how many items I have put in there (it is a buffer of stuff).

What is the best way to return a reference to this array in C++11 ?

Here are the things I have tried:

GetArray(Foo* &f[], unsigned &size) const

I like the syntax because it makes it clear that the reference value is an array of pointers, but this gives a compiler error: Declared as array of references of type Foo*

GetArray(Foo** &f, unsigned &size) const
{
  f = m;
  size = mSize;
}

Gives me: Error: assigning to Foo **' from incompatible type Foo *const[10]. Casting mFoo to (Foo**) alleviates the error, but IMHO, this is not elegant.

Upvotes: 0

Views: 257

Answers (3)

M.M
M.M

Reputation: 141618

Nobody posted an answer using std::array yet, it is a very simple replacement:

class Bar
{
    std::array<Foo *, 10>  m;
public:
    std::array<Foo *, 10> & getArray() { return m; }
    std::array<Foo *, 10> const & getArray() const { return m; }
};

This seems to me a lot simpler than the hoops you have to jump through to use your C-style array version.

To avoid code duplication you could typedef std::array<Foo *, 10> FooArray; .

The technique of having both a const and a non-const implementation is a common pattern for accessor functions which return a reference or a pointer. (It's not required if your accessor returns by value, of course).

Upvotes: 1

Richard Hodges
Richard Hodges

Reputation: 69892

here's another approach that returns the array reference and the current size as a tuple:

#include <tuple>
#include <functional>
#include <algorithm>
#include <iterator>
#include <iostream>

struct Foo {};

using FooBuffer = Foo*[10];

class Bar
{
public:
  Bar() 
  : _m { nullptr }
  {
      _m[0] = new Foo;
      _m[1] = new Foo;
      _items = 2;
  }

  ~Bar() {
      for(auto fp : _m)
        delete fp;
  }

  std::tuple<FooBuffer&, size_t> getInfo() {
      return std::make_tuple(std::ref(_m), _items);
  }
private:    
  Foo* _m[10];
  size_t _items;
};


int main() {
    Bar b;

    auto info = b.getInfo();
    FooBuffer& buf = std::get<0>(info);
    size_t items = std::get<1>(info);

    for(Foo** p = buf ; p != buf + items ; ++p) {
        std::cout << "Foo at " << std::hex << *p << std::endl;
    }

return 0;
}

Upvotes: 0

Galik
Galik

Reputation: 48625

I would seek to use a std::array or a std::vector in most cases. If you are determined to use a raw array then you could go this way with it:

typedef int Foo;

typedef Foo* (&FooPtrArrayRef)[10]; // to make the syntax less hairy

class Bar
{
private:
  Foo* m[10];

public:
  // First way without using typedef
  Foo* (&getArray())[10]
  {
      return m;
  }

  // Nicer looking way with a typedef
  FooPtrArrayRef getArrayByRef()
  {
      return m;
  }
};

int main()
{

    Bar b;

    Foo* (&array)[10] = b.getArray();

    std::cout << (sizeof(array) / sizeof(Foo*)) << '\n';

    // Alternative using "size deduction"

    Foo* (&array2)[sizeof(b.getArray()) / sizeof(Foo*)] = b.getArray();

    std::cout << (sizeof(array2) / sizeof(Foo*)) << '\n';

    // MUCH nicer using the typedef

    FooPtrArrayRef array3 = b.getArrayByRef();

    std::cout << (sizeof(array3) / sizeof(Foo*)) << '\n';
}

The syntax is pretty obscure though.

The benefits of this is approach is that it retains the full type information of the array you are passing by reference. The obscure syntax is necessary to avoid the type collapsing to a Foo**. By retaining the full type of the array you retain the ability to know its size at compile time using the sizeof() operator.

Upvotes: 1

Related Questions