2013-07-29 95 views
3
#include <iostream> 
#include <vector> 

using namespace std; 

class A { 
    private: 
    int number; 
    public: 
    A() {number = 0;} 
    A(int nr) {number = nr;} 
    //A(const A& rhand) {this->number = rhand.number;} 
    int get_number() const {return this->number;} 
    A& operator=(const A& rhand) { 
     this->number = rhand.number; 
     return (*this); 
    } 
}; 

class B { 
    private: 
    vector<A*>* content; 
    vector<A*>::iterator currA; 
    bool currA_valid; 
    public: 
    B() { 
     content = new vector<A*>; 
     currA = content->begin(); 
     currA_valid = false; 
    } 
    void push_A(A* nA) {content->push_back(nA); currA_valid = false;} 
    void push_A(A nA) {content->push_back(&nA); currA_valid = false;} 
    A get_A() { 
     if(!currA_valid) { 
     currA = content->begin(); 
     if(!content->empty()) { 
      currA_valid = true; 
     } 
     } 
     if(currA == content->end() || this->content->empty()) { 
     currA = content->begin(); 
     return A(); 
     } 
     else { 
     A result(**currA); 
     ++currA; 
     return result; 
     } 
    } 
}; 

int main() 
{ 
    B container; 

    A* a1 = new A(1); 
    cout << a1->get_number() << endl; 
    A a2(2); 
    cout << a2.get_number() << endl; 

    container.push_A(a1); 
    container.push_A(a2); 


    A tmp; 
    while((tmp = container.get_A()).get_number() != 0) 
    cout << "Inhalt tmp: " << tmp.get_number() << endl; 

    return 0; 
} 

最近我遇到了一個問題,我把它變成了這段代碼片段。爲什麼需要這個複製構造函數

本質上類B是類A

的對象在實際的碼A的容器被大得多和類型A相同的對象可能會出現在容器數次,所以爲了節省空間,乙只存儲指向A.

的B ::推功能飼料類型A的對象到容器中。

他們重載A.

while循環在主函數結束的指針和數值是我想要的東西(有點像流媒體運營商的使用iostream對象)。

B中的迭代器「currA」會跟蹤函數調用B :: get_A()最後返回的元素,因此對該函數的連續調用將返回B :: content中的所有A對象,直到結束到達了。在這種情況下,內部迭代器將被重置,並返回一個帶有內部無效標誌(此處爲簡單起見A :: number爲0)的對象A.

該程序的輸出可能看起來像這樣:

1 
2 
Inhalt tmp: 1 //content of a1 
Inhalt tmp: 4620996 //content of a2 

主要功能實例的兩個對象A A1(1)和A * A2(2)。

要測試顯示的內部值的A :: get_number()。兩者都按預期工作。但是,在我們將它們都送入容器並從中取出後,只能正確顯示a1。 a2的內容只顯示一些隨機數字。

起初我還以爲,我犯了一個錯誤的一些指針,但它證明了如果一個聲明的問題是固定的,定義這樣的拷貝構造A類:

A(const A& rhand) {this->number = rhand.number;} 

據據我瞭解,複製構造函數將由C++編譯器隱式定義,如果沒有提供,並且建議實現它,當類有指針作爲成員以避免淺拷貝時。但在這種情況下,A只有一個int。

我還試圖通過擺脫B :: get_A()並獲得通過其他手段的容器的內容的,以簡化的代碼。即使沒有實現默認構造函數,問題也消失了。 因此,這裏是我的問題:

1)是不是拷貝構造函數,編譯器定義了類似我提供的一個?

2.)拷貝構造函數甚至與實際問題有什麼關係?如何實現複製構造函數解決問題?

+0

使用初始化列表代替體內分配來初始化類別分支。 – Manu343726

+2

在'push_back'的第二個重載中存儲着一個指向本地副本的指針,所以在push_back結束之後,該指針是無效的。 – Manu343726

回答

2
void push_A(A nA) {content->push_back(&nA); currA_valid = false;} 

在這裏,您按價值取A對象。該對象是該函數的本地對象。當函數返回時,對象不再存在,所以你的向量留下一個無效指針。

你實現拷貝構造函數無關與解決問題,這只是一個巧合。

+0

我已經注意到,正如你在評論中看到的那樣,但這不是OP問題的答案。它的評論。 – Manu343726

+0

@Manu343726:這可能不是OP問題的答案,但它是解決他的問題的方法。 –

+0

不,它不是解決方案。它的錯誤與問題有關。問題不在於存儲指向副本的指針(是的,那是一個錯誤,但不是錯誤的問題),是做一個沒有拷貝構造函數的副本。解決辦法是建議OP研究三條規則。 – Manu343726

0

是的,如果沒有提供複製構造函數,編譯器會寫入它。但是,如果您定義了自己的assigment操作符或析構函數,則應該定義自己的copy-ctor實現。一般來說,如果你編寫一個構造函數(Copy-ctor,assigment operator,和/或析構函數)的實現,你必須編寫你自己的其他實現。

這就是所謂的「The Rule Of Three」。

+0

這是錯誤的。三個規則的存在是爲了讓程序員遵循* us。編譯器不遵守這樣的規則。它可以並將在所有情況下實現複製構造函數(無論是否定義了賦值運算符或析構函數),除非默認實現不明確。 –

+0

@BenjaminLindley是的,三條規則是一條經驗法則,而不是編譯器的規則。但那不是重點。關鍵是要了解代碼爲什麼會產生錯誤,以及解決它的規則。 – Manu343726

+0

*「但是,如果你定義了你自己的assigment操作符或析構函數,那麼編譯器不允許提供copy-constructor的實現。」* - 這就是關鍵所在,這是錯誤的。 –

相關問題