2009-10-12 57 views
0

在我的代碼中,我有一個Student對象的向量。在C++中,如何在保持指向對象的指針的同時將對象推入矢量?

vector<Student> m_students; 

我想:看到

  1. 檢查載體含有一定名稱的任何學生。
  2. 如果沒有這樣的學生存在,添加一個新的。
  3. 將數據添加到該名稱的學生。

考慮下面的代碼:

// Check to see if the Student already exists. 
Student* targetStudent = NULL; 
for each (Student student in m_students) 
{ 
    if (student.Name() == strName) 
    { 
     targetStudent = &student; 
     break; 
    } 
} 

// If the Student didn't exist, add it. 
if (targetStudent == NULL) 
{ 
    targetStudent = new Student(strName); 
    m_students.push_back(*targetStudent); 
} 

// Add the course info to the Student. 
targetStudent->Add(strQuarter, strCourse, strCredits, strGrade); 

當我撥打電話到m_students.push_back(*targetStudent);似乎矢量「m_students」結束了Student對象的副本「targetStudent」指向那個時間。

隨後嘗試添加到targetStudent不會更改向量中包含的對象。

我該如何從一個指向對象的指針開始,將該對象添加到一個矢量,然後訪問該矢量中的對象?

回答

6

STL容器複製它們包含的對象。沒有辦法解決這個問題。

但是,您可以有一個std::vector<std::shared_ptr<Student> >,它允許您有一個智能指針的容器。然而,爲了實現這個目標,在施工時,您的物體必須全部附加到shared_ptr

所以,像:

std::vector<std::shared_ptr<Student> > m_students; 

std::shared_ptr<Student> targetStudent; 
for each (std::shared_ptr<Student> student in m_students) 
{ 
     if (student->Name() == strName) 
     { 
       targetStudent = student; 
       break; 
     } 
} 

// If the Student didn't exist, add it. 
if (!targetStudent) 
{ 
     // creates a new Student and attaches it to smart pointer 
     targetStudent.reset(new Student(strName)); 
     m_students.push_back(targetStudent); 
} 

std::shared_ptr在C++ 11的<memory>頭被定義。 (在TR1中,您可以改爲使用std::tr1::shared_ptr。)如果您使用的是不帶TR1的C++ 98,或者需要隨便攜帶它,則可以使用boost::shared_ptr代替;從Boost下載。

+0

我會建議在引用標準名稱空間時總是使用:: std而不是std。如果有人曾經自己創建了名爲'std'的命名空間(當然不是頂級的,那將是不合法的),那麼在某些情況下,最終可能會出現含糊不清或意外解決的std引用。 – Omnifarious 2009-10-12 04:25:01

+0

@Omnifarious有些人也可能會做'#define std foo'。你無法準備那裏的每一個白癡。 – 2012-03-23 23:06:03

+0

@quant_dev:這不是因爲有人可能在另一個命名空間內創建名爲'std'的命名空間。這是因爲你總是習慣於用你指的名字來引用命名空間,而不是今天似乎工作的最方便的名稱。 – Omnifarious 2012-03-23 23:16:57

9

得到的指針的對象時,它被插入載體後,這樣反而

targetStudent = new Student(strName); 
m_students.push_back(*targetStudent);

使用

 
m_students.push_back(Student(strName)); 
targetStudent = &m_students.back(); 

另外請注意,你的榜樣泄漏內存,複製到矢量targetStudent永遠不會被刪除。另外請記住,添加新元素時,向量中的指針變爲無效(如果向量在物理大小上增加並且元素必須被複制到新的更大的向量中,所有指向前一個緩衝區的指針變爲無效) 。

+0

這比'shared_ptr'提議更簡單得多,因此更好。 – MSalters 2009-10-12 09:22:45

+0

我剛纔重讀了這個答案,並且同意我也喜歡它。 +1我也同意MSalters所說的話,即使我寫了'shared_ptr'答案,如果OP選擇了這個答案或Jerry的答案,我也不會有任何問題,兩者都非常出色。 :-) – 2009-10-12 14:50:28

+0

+1這實際上非常類似於我在Chris指出容器總是複製之後做的結果。 也感謝您指出內存泄漏(我習慣於垃圾收集語言,並且經常不必考慮堆)。 – 2009-10-14 17:15:06

5

您已經對您的問題得到了合理直接的答案。然而,基於你似乎試圖完成的事情,在我看來,一個較不直接的答案可能確實是一個更好的答案。

至少在我閱讀你的描述時,你有許多獨特的學生,併爲每個學生提供了一些課程。當一個學生完成一門課程後,你想尋找學生。如果他們不在收藏中,請添加它們。然後爲他們完成的課程添加數據。

既然如此,一個向量就是一個不理想的解決方案。您可以實現代碼幾種不同的方式,但我可能會做這樣的:

struct course { 
    std::string Quarter_, Course_, Credits_, Grade_; 

    using std::string; 
    course(string const &q, string const &c, string const &cr, string const &g) 
     : Quarter_(q), Course_(c), Credits_(cr), Grade_(g) 
    {} 
}; 

std::map<std::string, std::vector<course> > m_students; 

利用這一點,來查找學生的整個序列,插入一個新的學生如果沒有一個通過這個名字,然後添加課程作業的(新的或現有的)學生的記錄將制定出爲:

m_students[strName].push_back(course(strQuarter, strCourse, strCredits, strGrade)); 

再回到你原來的問題,標準容器旨在與工作。您向他們傳遞一個值,並且存儲該值的副本。其中一個後果就是,像push_back(new XXX)這樣的東西本質上是總是一個錯誤(幾乎保證了內存泄漏)。如果你有一個對象,只要通過它。如果你不這樣做,只需創建一個臨時文件並通過即可。在爪哇(舉一個例子),看到new XXX到處都是例行公事,幾乎是不可避免的。雖然你也可以用這個方式編寫C++,但這並不是你應該期望的。

+1

+1 Yay爲了看大圖! :-D – 2009-10-12 14:48:19

+0

+1你說得對,這更像我想要的...如果我的目標是創建一個真正的應用程序。不幸的是,這是爲了一個學校的任務,教授對我們應該使用什麼樣的數據結構非常具體,並且沒有這種創造性的空間。 – 2009-10-14 17:11:56