引用不同大小的std::array,而不是基类中的std::array

Reference to std::array of different sizes instead of std::array in a base class

本文关键字:array std 基类 引用      更新时间:2023-10-16

我有以下问题。考虑类

class face {
    virtual std::vector<ptr>& get_vertices(void) const = 0;
};
class triangle : public face {
private:
    std::vector<ptr> vertices;
public:
    std::vector<ptr>& get_vertices(void) const { return vertices; };
};
class quadrilateral : public face {
private:
    std::vector<ptr> vertices;
public:
    std::vector<ptr>& get_vertices(void) const { return vertices; };
};

显然,三角形和四边形总是分别有3个和4个顶点。因此,我想通过适当大小的std::数组来交换std:向量,以节省std:矢量中三个额外指针所引起的开销。(这是因为我将拥有数百万个面……)现在,有没有机会像上面的std::vector一样,在std::array的面中拥有一个通用的访问函数?对于标准的C数组,我只需返回一个指向第一个数组条目及其大小的指针。有没有STL方法可以做同样或类似的事情?或者还有其他很好的方法来实现这个功能吗?

感谢您的阅读和可能的回答!!Andreas

不同大小的std::arrays是不同的类型,所以我看不出有什么方法可以做你想做的。但是,如果您将begin()end()常量迭代器返回到您内部持有的任何容器,或者返回一个包含两者的小范围对象,该怎么办?通过这种方式,可以将容器的大小与接口解耦,将其留给实现。

EDIT:为了澄清,为了隐藏数据存储表示(在本例中为std::array的大小),您需要自己的face迭代器类。这在指针方面很容易实现,因为对于每个face专门化,您都知道底层数据结构的大小、开始和结束。但很明显,您不能在接口中直接使用std::arraybegin()end()

示例:

这是一个快速而肮脏的示例,说明了如何使用指针实现部分前向迭代器行为。我使用虚拟基类和OP中的一个实现作为起点。我还省略了所有的构造函数、赋值运算符等。它还假设了一个类Edge(可能是2D或3D点?)。

class face {
public:
  typedef Edge* iterator;
  typedef const Edge* const_iterator;
  virtual iterator begin() = 0;
  virtual const_iterator begin() const = 0;
  virtual iterator end() = 0;
  virtual const_iterator end() const = 0;
  virtual size_t size() const = 0;
  virtual ~face() {};
};
class triangle : public virtual face {
public :
  virtual iterator begin() {return m_edges.begin();}
  virtual const_iterator begin() const {return m_edges.begin();}
  virtual iterator end() {return m_edges.end();}
  virtual const_iterator end() const {return m_edges.end();}
  virtual size_t size() const {return m_edges.size();}
private:
    std::array<Edge, 3> m_edges;

};

std::array在这里似乎不是一个解决方案,因为get_vertices是一个纯虚拟函数,也就是说,您希望使用基类类型的指针(或引用)来访问它。如果你使用std::array,你必须提供一个整数值作为std::array类模板的第二个参数,这是可能的,如果你让face成为一个类模板,类似这样:

template<size_t N>
class face {
    virtual std::array<ptr, N>& get_vertices(void) const = 0;
};
class triangle : public face<3>{
    //...
    std::array<ptr, 3>& get_vertices(void) const { return vertices; };
};
class quadrilateral : public face<4> {
    //...
    std::array<ptr, 4>& get_vertices(void) const { return vertices; };
};

但这导致trianglequadrilateral具有不同的基类:face<3>face<4>是两个不同的类。这意味着,不能将trianglequadrilateral混合在一起,例如在标准容器中,也不能使用相同基类类型的指针访问get_vertices,因为现在没有单个基类。每个派生类都有自己的基类。

因此,解决方案是:

class triangle : public face {
private:
    std::vector<ptr> vertices;
public:
    triangle() 
    {
           //it ensures that you've a vector of size 3, no more no less 
           vertices.reserve(3); 
    }
    std::vector<ptr>& get_vertices(void) const { return vertices; };
};

类似地,您可以在quadrilateral:中执行

    quadrilateral() 
    {
           //it ensures that you've a vector of size 4, no more no less 
           vertices.reserve(4); 
    }

现在,您的向量不会随意将自己调整为比实际需要的更大的大小,因为您已经通过调用reserve()定义了容量,您将添加比其容量更多的项目。不会调整大小。