2011-01-20 344 views
1

我正在通過Accelerated C++的方式工作,並決定解決那裏定義的結構之一。雖然這樣做,但我遇到了一個問題:創建這些結構的向量並修改每個結構中的元素似乎都會修改其中的所有元素。我知道這可能意味着我已經將向量中的所有結構初始化爲單個內存地址處的結構,但我使用.push_back()方法將「虛擬」結構插入到向量中。我的印象是.push_back()推入了它的參數副本,有效地創建了一個新的結構體。C++:爲什麼我的向量結構作爲一個結構?

下面是結構的標題:

#ifndef _STUDENT_INFO__CHAPTER_9_H 
#define _STUDENT_INFO__CHAPTER_9_H 

#include <string> 
#include <iostream> 
#include <vector> 

class Student_info9{ 
public: 
    Student_info9(){homework = new std::vector<double>;}; 
    Student_info9(std::istream& is); 

    std::string getName() const {return name;}; 
    double getMidterm() const {return midterm;}; 
    double getFinal() const {return final;}; 
    char getPassFail() const {return passFail;}; 

    std::vector<double> *getHw(){return homework;}; 

    void setName(std::string n) {name = n;}; 
    void setMidterm(double m) {midterm = m;}; 
    void setFinal(double f) {final = f;}; 


private: 
    std::string name; 
    double midterm; 
    double final; 
    char passFail; 

    std::vector<double> *homework; 
}; 


#endif /* _STUDENT_INFO__CHAPTER_9_H */ 

這裏是我與(原諒過度print語句打打鬧鬧的代碼......一段時間嘗試調試結果:) ):

vector<Student_info9> did9, didnt9; 

bool did_all_hw9(Student_info9& s) 
{ 
    vector<double>::const_iterator beginCpy = s.getHw()->begin(); 
    vector<double>::const_iterator endCpy = s.getHw()->end(); 
    return(find(beginCpy, endCpy, 0) == s.getHw()->end()); 
} 

void fill_did_and_didnt9(vector<Student_info9> allRecords) 
{ 
    vector<Student_info9>::iterator firstDidnt = partition(allRecords.begin(), allRecords.end(), did_all_hw9); 


    vector<Student_info9> didcpy(allRecords.begin(), firstDidnt); 


    did9 = didcpy; 

    vector<Student_info9> didntcpy(firstDidnt, allRecords.end()); 
    didnt9 = didntcpy; 


} 

int main(int argc, char** argv) { 

    vector<Student_info9> students; 

    Student_info9 record; 

    for(int i = 0; i < 5; i++) 
    { 
     students.push_back(record); 
    } 

    for(int i = 0; i < students.size(); i++) 
    { 
     students[i].setMidterm(85); 
     students[i].setFinal(90); 

     students[i].getHw()->push_back(90); 
     std::cout << "student[" << i << "]'s homework vector size is " << students[i].getHw()->size() << std::endl; 
     students[i].getHw()->push_back(80); 
     std::cout << "student[" << i << "]'s homework vector size is " << students[i].getHw()->size() << std::endl; 
     students[i].getHw()->push_back(70); 
     std::cout << "student[" << i << "]'s homework vector size is " << students[i].getHw()->size() << std::endl; 

     std::cout << "Just pushed back students[" << i << "]'s homework grades" << std::endl; 

     if(i == 3) 
      students[i].getHw()->push_back(0); 
    } 

    std::cout << "student[3]'s homework vector size is " << students[3].getHw()->size() << std::endl; 

    for(vector<double>::const_iterator it = students[3].getHw()->begin(); it != students[3].getHw()->end(); it++) 
     std::cout << *it << " "; 

    std::cout << std::endl; 

    std::cout << "students[3] has " << ((find(students[3].getHw()->begin(),students[3].getHw()->end(), 0) != students[3].getHw()->end()) ? "atleast one " : "no ") 
      << "homework with a grade of 0" << std::endl; 

    fill_did_and_didnt9(students); 


    std::cout << "did9's size is: " << did9.size() << std::endl; 
    std::cout << "didnt9's size is: " << didnt9.size() << std::endl; 

} 

正如你可以打印報表看,似乎功課成績被添加到只有一個Student_info9對象,其副本似乎填充整個矢量。我的印象是,如果您要在單個對象上使用連續的.push_back()副本,則會創建該對象的副本,每個副本具有不同的內存地址。

我不確定這是否是問題的根源,但希望有人能指出我正確的方向。

謝謝。

+0

順便說一下,這些標頭警衛[非法](http:// stackoverflow。COM /問題/ 228783 /什麼,是最規則有關,使用安下劃線-IN-A-C-標識符)。 – GManNickG 2011-01-20 17:48:47

回答

4

當您將StudentInfo推入矢量時,它確實被複制,所以這不是問題。問題是包含作業成績的媒介。由於您只在StudentInfo中存儲指向該向量的指針,因此在複製StudentInfo時,只會複製指針而不是向量。換句話說,你有許多不同的StudentInfos,它們都有一個指向相同作業向量的指針。

要解決這個問題,你應該定義一個複製構造函數,它負責複製作業矢量。

+0

好吧,我不是創建一個複製構造函數,而是解除了「new」語句返回的內容,並使作業矢量成爲一個實際的矢量(而不是一個指針)。我還改變了getHw()返回一個向量而不是一個指針,並將相應的「 - >」運算符更改爲「。」。 main()中的運算符。現在的問題是沒有任何家庭作業成績被添加到Student_info9作業載體中!我認爲默認的複製構造函數複製每個字段,所以我不知道爲什麼這不起作用 – Kevin 2011-01-20 15:43:05

+0

@Kevin:1.如果你不需要指針,你不應該使用`new`。 2.除非你讓`getHw`方法返回一個指針或引用,否則它會返回一個向量的副本。所以,如果你做'students [i] .getHw()。push_back(0)``你給`getHw`返回的副本加0,而不是`student [i]`的作業向量。 – sepp2k 2011-01-20 15:48:01

2

您是否瞭解了複製構造函數?如果是這樣,請考慮在push_back()vector<Student_info9> students發生了什麼。

具體來說,這個指針會發生什麼。

std::vector<double> *homework; 
1

Student_info9 record;使用第一個構造函數構造一個Student_info9。這第一個構造函數創建一個向量並將其指針存儲爲成員變量。然後繼續將這個Student_info9的副本添加到一個向量中5次。每個副本都有一個指向同一個向量的指針。

1

StudentInfo9類contanis一個指向std::vector<double>,這意味着在默認的拷貝構造函數(當您添加StudentInfo9對象的載體,其將被稱爲),指針本身被複制。這意味着所有的StudentInfo9對象都有相同的作業矢量。

這有道理嗎?請參閱http://pages.cs.wisc.edu/~hasti/cs368/CppTutorial/NOTES/CLASSES-PTRS.html以獲得更深入的指針和複製構造函數。

相關問題