2015-06-27 71 views
8

我想弄清楚如何遍歷一個容器(如std :: vector)的對象在內存中共享一個公共基類父類連續迭代遍歷內存中的公共基類的對象

爲了演示這個問題,我們使用下面的例子。現在

class Base 
{ 
public: 
    Base(); 
    virtual void doStuff() = 0; 
}; 

class DerivedA : public Base 
{ 
private: 
    //specific A member variables 
public: 
    DerivedA(); 
    virtual void doStuff(); 
}; 

class DerivedB : public Base 
{ 
private: 
    //specific B member variables 
public: 
    DerivedB(); 
    virtual void doStuff(); 
}; 

,使用std :: vector的迭代會保持在連續內存中的對象,但我們會體驗到切片,因爲沒有空間的派生屬性。

因此,我們必須使用多態技術使用指針像這樣

int main() 
{ 
    std::vector<Base*> container; 
    container.push_back(new DerivedA()); 
    container.push_back(new DerivedB()); 

    for (std::vector<Base*>::iterator i = container.begin(); i!=container.end(); i++) 
    { 
     (*(*i)).doStuff(); 
    } 
} 

據我知道,應該工作正常鑑於類實現。

問題:現在 ,載體含有指針在連續內存中,但這並不意味着它們都指向地址。

因此,如果我希望能夠隨時刪除對象並將其插入到矢量中,那麼這些對象將遍佈整個內存中。

問: 好像每個人建議做它的std ::向量的方式,但爲什麼沒有考慮問題的是,它不是在內存中連續可迭代(假設我們實際使用的指針)?

我是否被迫做了複製麪食的方式?

int main() 
{ 

    std::vector<DerivedA> containerA; 
    DerivedA a; 
    containerA.push_back(a); 

    std::vector<DerivedB> containerB; 
    DerivedB b; 
    containerB.push_back(b); 

    for (std::vector<DerivedA>::iterator i = containerA.begin(); i!=container.end(); i++) 
    { 
     (*i).doStuff(); 
    } 
    for (std::vector<DerivedB>::iterator i = containerB.begin(); i!=container.end(); i++) 
    { 
     (*i).doStuff(); 
    } 
} 

我猜可能沒有真正解決這一點,因爲在內存中保存各種大小的物體線性並沒有真正意義,但如果任何人都可以給我一些意見,我將不勝感激。

+0

我認爲你最後一句話總結了它。如果你無法忍受複製粘貼,也許使用容器來管理你的載體。如果你想要一些想法,我已經在[這裏](http://codereview.stackexchange.com/questions/87729/storing-collections-of-objects-of-any-type)刺了一刀。 – Quentin

+0

Offhand我可以想象一種方法來保持內存中的連續類型。但是你會失去隨機訪問,並可能有其他限制。事實上,它有點像在同一時間獲得矢量和列表的最壞方面。與軟件開發中的大部分內容一樣,在某個地方有一個權衡。 – TheUndeadFish

+3

它們的尺寸有多大?對於他們採用派生大小的大數,再加上一個指針或頭頂的指針,你還好嗎?你是否使用繼承來實現多態?界面有多大?你有提升嗎?派生類的集合是否被修正(在編譯時)並且有界?這些不是閒置的問題,對它們的回答可以使某些解決方案可行,而其他方案則不行。 – Yakk

回答

-3

std::vector<T>迭代假定在連續的存儲器中的對象是T類型,std::vector<T>::iterator::operator++認爲sizeof T是不變 - 即,它不參考特定實例爲大小的數據。

在本質上,你能想到的vectorvector::iterator爲薄的外觀在T* m_data指針,這樣iterator++真的只是一個基本的指針操作。

您可能需要使用自定義分配器和就地new準備資料,並伴有兩種索引,鏈接等或許認爲像http://www.boost.org/doc/libs/1_58_0/doc/html/intrusive/slist.html

參見boost::stable_vector

+0

鏈接列表在內存中永遠不會是連續的,我不明白這是如何回答這個問題的,也不知道它如何有效地不同於一個向量>。 –

-3

std::vector分配對象在連續的內存中,但你存儲在向量中的對象指針不是。這是你通過vector迭代的方式。以下代碼是用C++ 14編寫的。所描述的問題不能通過該解決方案解決,因爲對象指針被存儲在連續的存儲器中而不是實際的對象中。

#include <iostream> 
#include <memory> 
#include <vector> 
#include <algorithm> 
using namespace std; 

class Base 
{ 
public: 
    Base() {} 
    virtual void doStuff() = 0; 
}; 

class DerivedA : public Base 
{ 
private: 
    //specific A member variables 
public: 
    DerivedA() : Base() {} 
    virtual void doStuff() { 
     std::cout << "Derived Class A - Do Stuff" << std::endl; 
    } 
}; 

class DerivedB : public Base 
{ 
private: 
    //specific B member variables 
public: 
    DerivedB() : Base() {} 
    virtual void doStuff() { 
     std::cout << "Derived Class B - Do Stuff" << std::endl; 
    } 
}; 
int main() { 
    // your code goes here 
    std::vector<std::unique_ptr<Base> > container; 
    container.push_back(std::make_unique<DerivedA>()); 
    container.push_back(std::make_unique<DerivedB>()); 

    std::for_each(container.begin(), container.end(),[](std::unique_ptr<Base> & b) { 
     b->doStuff(); 
    }); 
    return 0; 
} 

現場演示here

+0

_「'std :: vector'不分配連續內存中的所有對象」_是的,它的確如此。你甚至沒有接近回答這個問題。自四年前以來,它一直不是「C++ 0x」。它變成了C++ 11。甚至那個已經被C++ 14取代,這也相對較舊... –

+0

是的,這是正確的。我一直在C++ 14本身運行這個代碼。我的意思是說,這些對象不會被分配在連續的記憶中。我會更新答案 –

+0

是的,矢量元素總是分配在連續的內存中。在你的情況下,這些元素是指針,指針仍然分配在連續的內存中。 –