返回对大小不变的指针数组的引用的最佳方式是什么

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

本文关键字:引用 数组 最佳 方式 是什么 指针 返回      更新时间:2023-10-16

我有一个指针数组,声明为类成员,如下所示:

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

在我的一个类方法中,我想返回一个指向这个数组的指针(或者最好是一个引用)。数组在编译时有一个已知的大小,但我会记录我在其中放入了多少项(它是一个缓冲区)。

在C++11中,返回对此数组的引用的最佳方式是什么?

以下是我尝试过的东西:

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

我喜欢这种语法,因为它清楚地表明引用值是指针数组,但这会导致编译器错误:Declared as array of references of type Foo*

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

给我:错误:分配给Foo **' from incompatible type Foo *const[10]。将mFoo转换为(Foo**)可以减轻错误,但IMHO,这并不优雅。

还没有人使用std::array发布答案,这是一个非常简单的替代:

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

在我看来,这比使用C风格数组版本所需的困难要简单得多。

为了避免代码重复,您可以typedef std::array<Foo *, 10> FooArray;

同时具有const和非const实现的技术是返回引用或指针的访问器函数的常见模式。(当然,如果您的访问器按值返回,则这不是必需的)。

在大多数情况下,我会寻求使用std::arraystd::vector。如果你决定使用一个原始数组,那么你可以这样做:

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

不过,语法相当晦涩。

这种方法的好处是,它保留了通过引用传递的数组的完整类型信息。模糊语法对于避免类型塌陷为Foo**是必要的。通过保留数组的完整类型,您可以在编译时使用sizeof()运算符来了解其大小。

这里有另一种方法,它将数组引用和当前大小作为元组返回:

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