2011-01-20 41 views
1

私はAccelerated C++を使って作業を進めており、そこに定義されている構造体を使いこなすことに決めました。そうしているうちに、私は問題に遭遇しました。これらの構造体のベクトルを作成し、それぞれの要素を変更することは、それらの要素のすべてを変更するようです。C++:なぜ構造体のベクトルが1つの構造体として機能していますか?

これはおそらく、ベクトルのすべての構造体を単一のメモリアドレスで構造体に初期化したことを意味しますが、私は.push_back()メソッドを使用してベクトルに "ダミー"構造体を挿入しました。私は.push_back()がその引数のコピーをプッシュし、効果的に新しい構造体を作成しているという印象を受けました。ここで

は、構造体のヘッダーです:

#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文を言い訳に浮気していたコードです:) ):あなたは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

ところで、これらのヘッダーガードは[illegal](http:// stackoverflow。com/questions/228783/what-are-the-rules-about-an-c-identifierのアンダースコアを使用して) – GManNickG

答えて

4

StudentInfoをベクトルにプッシュすると、実際にはコピーされているので問題はありません。問題は、宿題を含むベクトルです。 StudentInfoにそのベクトルへのポインタしか格納しないので、StudentInfoをコピーするときにベクトルではなくポインタだけがコピーされます。言い換えれば、同じ宿題ベクトルへのポインタを持つ多くの異なるStudentInfoがあります。

これを解決するには、宿題ベクトルのコピーを処理するコピーコンストラクタを定義する必要があります。

+0

OK、コピーコンストラクタを作成するのではなく、 "new"ステートメントによって返されたものを逆参照し、宿題ベクトルを実際のベクトル(ポインタを指すポインタではなく)にしました。また、getHw()をポインタへのポインタではなくベクトルを返すように変更し、適切な " - >"演算子を ""に変更しました。 main()の演算子。問題は、宿題がStudent_info9の宿題ベクトルに追加されていないことです。私はデフォルトのコピーコンストラクタがすべてのフィールドをコピーしたと思ったので、なぜこれがうまくいかないのか分かりませんでした。 – Kevin

+0

@ケビン:1.ポインタを必要としない場合は 'new'を使うべきではありません。 2. 'getHw'メソッドがポインタや参照を返さない限り、ベクトルのコピーを返します。だから 'students [i] .getHw()。push_back(0)'を実行すると、 'student [i]'の宿題ベクトルではなく、 'getHw'によって返されたコピーに0が追加されます。 – sepp2k

+0

ああ、持っています。もう1つの質問。 getHw()は、宿題ベクトルそのものではなく、宿題ベクトルのコピーを返します。呼び出し元のオブジェクトに適用されるconstキーワードのためですか? – Kevin

2

コピーコンストラクタについてまだ学習しましたか?もしそうなら、vector<Student_info9> studentsで何が起こっているのかをpush_back()と考えてください。

具体的には、このポインタはどうなりますか。

std::vector<double> *homework; 
1

Student_info9 record;は、最初のコンストラクタを使用してStudent_info9を構築します。この最初のコンストラクタはベクトルを作成し、その変数へのポインタをメンバ変数として格納します。次に、このStudent_info9のコピーをベクトルに5回追加します。各コピーには同じベクトルへのポインタがあります。

+0

簡潔;これが答えとして受け入れられなかった唯一の理由は、決議がないということです。診断だけです。しかし、素晴らしい答え。 – Kevin

1

StudentInfo9クラスcontanisは、へのポインタです。つまり、デフォルトのコピーコンストラクタ(ベクターにStudentInfo9オブジェクトを追加すると呼び出されます)では、ポインタ自体がコピーされます。つまり、すべてのStudentInfo9オブジェクトにはと同じ宿題ベクトルがあります。

それは意味がありますか?ポインターとコピーコンストラクターの詳細については、http://pages.cs.wisc.edu/~hasti/cs368/CppTutorial/NOTES/CLASSES-PTRS.htmlを参照してください。

関連する問題