2011-05-29 54 views
3

我遇到以下問題。考慮類引用不同大小的std :: array而不是基類中的std :: array

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 :: array來交換std :: vector以保存std :: vector中三個附加指針引發的開銷。 (這是因爲我將擁有數百萬的面孔......)現在,是否有機會與std :: vector一起使用std :: array的通用訪問函數? 使用標準的C數組,我只需返回一個指向第一個數組項和它的大小的指針。是否有STL方式來做相同或類似的事情?或者有沒有其他很好的方法來實現這個功能?

感謝您的閱讀並可能回答! Andreas

+0

你在說什麼'std :: vector'中的額外指針? – Nawaz 2011-05-29 08:27:45

+0

你真的需要將它們作爲STL容器返回嗎?如果只有3或4個元素,我在矢量或數組中看不到多少優勢。我只是將指針存儲在一個固定大小的數組中,並有一些直接返回元素的函數或運算符,比如'virtual ptr&operator [](unsigned idx);'和另一個用於計算它們的函數。 – Timo 2011-05-29 09:01:25

+0

@Nawaz:std :: vector的實現(至少對於gcc)除了存儲的數據本身之外,還使用三個指針來開始存儲,完成存儲和結束存儲。如果一個包含大量std :: vectors且條目相對較少,則這成爲無可忽略的開銷。 – Andreas 2011-05-29 18:53:33

回答

6

std::arrays不同大小是不同的類型,所以我看不到任何方式做你想做的。但是如果你將常量迭代器的begin()end()返回給你內部容納的任何容器,或者包含兩者的小範圍對象?這樣你就可以將容器的大小從接口中分離出來,留給實現。

編輯:只是爲了澄清,爲了隱藏數據存儲表示(在這種情況下,std::array的大小),你需要自己的迭代器類face。這在指針方面很容易實現,因爲對於每個face專業化您都知道底層數據結構的大小,開始和結束。但顯然,您不能在界面中直接使用std::arraybegin()end()

實施例:

這是示出了如何實現使用指針正向迭代器行爲的一部分的快速和骯髒的例子。我使用虛擬基類和OP的一個實現作爲起點。我也省略了所有的構造函數,賦值運算符等。它還假定類邊(可能是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; 

};

+0

這似乎是一個合適的解決方案。然而,我認爲可能有一個「更好的」解決方案,即已經實現了一些與數組大小無關的迭代器。無論如何,非常感謝! – Andreas 2011-05-29 19:34:09

+0

@Andreas,我添加了一個簡單的例子,只是爲了給出一個簡單的實現的想法。請小心處理,它是在匆忙中完成的! – juanchopanza 2011-05-30 06:41:34

1

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()來定義容量,並且您將添加比容量更多的項目。沒有調整大小發生。

+0

正如我在上面的評論,這隻會讓我從「昂貴」的重新分配,而不是從std :: vector的誘導開銷。 – Andreas 2011-05-29 19:00:58