2012-01-27 60 views
3

我有以下主要功能,使用指針創建係數的乘積。這只是項目的一小部分,用於創建多項式:C++覆蓋已定義的變量

#include "header.h" 
int main() 
{ 
    TermProd x = TermProd(new Coeff(4), new Coeff(8)); 
    x.print(); cout << endl; 
    x = TermProd(new Coeff(8), new Coeff(15)); 
    x.print(); cout << endl; 
    return 0; 
} 

經過測試,覆蓋似乎正在工作。但是當我打電話給x時,出現了分段錯誤。我一直在努力並盯着它很長一段時間,但我無法弄清真正的問題。此外,我的搜索沒有導致正確的方向,所以我決定創建一個重現錯誤的小代碼片段。

我header.h文件看起來像:

class Term{ 
public: 
    Term(){}; 
    virtual ~Term(){}; 
     virtual Term* clone() const = 0; 
    virtual void print() const = 0; 
}; 

class Coeff:public Term{ 
    int m_val; //by def: >=0 
public: 
    // Constructor 
    Coeff(); 
    Coeff(int val = 1):m_val(val) 
    // Copy constructor 
    Coeff* clone() const{return new Coeff(this->val());} 
    // Destructor 
    ~Coeff(){} 
    // Accessors 
    int val() const{return m_val;} ; 
    // Print 
    void print() const{cout << m_val; } 
}; 

class TermProd:public Term{ 
    TermPtr m_lhs, m_rhs; 
public: 
    // Constructor 
    TermProd(TermPtr lhs, TermPtr rhs):m_lhs(lhs), m_rhs(rhs){ } 
    // Copy constructor 
    TermProd* clone() const 
    { 
     return new TermProd(m_lhs->clone(), m_rhs->clone()); 
    } 
    // Destructor 
    ~TermProd(){ delete m_lhs;delete m_rhs;} 
    // Accessors 
    Term* lhs() const { return m_lhs; } 
    Term* rhs() const { return m_rhs; } 
    // Print 
    void print() const 
    { 
     cout << "("; m_lhs->print(); cout << '*'; m_rhs->print(); cout << ")"; 
    }  
}; 
+2

閱讀此:[規則3](http://stackoverflow.com/questions/4172722/what-is-the-rule-of -ree) – 2012-01-27 15:54:09

+0

@Michael它會生成一個臨時對象,它將被分配給第一個對象。 – AlexTheo 2012-01-27 15:57:47

回答

3

你沒有關注的Rule of Three
通過調用分配的指針成員隱式拷貝構造函數delete來銷燬函數調用期間創建的臨時變量。

您需要提供您自己的複製構造函數和複製賦值運算符,這將構成動態分配的指針成員的深層副本。

3

您不提供複製構造函數。你有一個clone方法,該評論說是複製構造函數,但它不是。

嘗試類似:

TermProd(TermProd const & other) 
    m_lhs(other.m_lhs->clone()), 
    m_rhs(other.m_rhs->clone()) 
{ 
} 

27:11其他類。

更新正如評論中指出的那樣,您還需要一個賦值運算符

TermProd & operator=(TermProd const & other) 
{ 
    if (this != &other) // Check for assignment to self. 
    { 
    delete m_lhs; 
    delete m_rhs; 
    m_lhs = other.m_lhs->clone(); 
    m_rhs = other.m_rhs->clone(); 
    } 
    return *this; 
} 
+1

然後'clone()'可以簡化爲'return new TermProd(* this);'。 – 2012-01-27 15:58:42

+0

我不認爲這是這裏的問題。錯誤的代碼是調用'operator ='而不是複製構造函數 – JaredPar 2012-01-27 15:59:35

+0

您將需要一個複製賦值操作符'TermProd&operator =(TermProd const&);' – 2012-01-27 15:59:48

6

注意這裏你是不是覆蓋x變量,而是分配給它。這將調用爲您的類型的默認operator=這大致將導致執行

下面的代碼
  1. TermProd::TermProd(TermPtr, TermPtr)執行
  2. m_lhsm_rhs構造被複制到值x
  3. 的析構函數在步驟#1中創建的值現在運行並且m_lhsm_rhs被刪除

此時喲你有一個真正的問題。在步驟#2之後,值x和步驟#1中創建的臨時值共享相同的值m_lhsm_rhs值。步驟#3析構函數刪除它們,但x仍然對它們的引用這是現在有效地死內存

指着爲了解決這個問題,你需要添加自己的operator=其正確處理分配語義。例如

TermProd& operator=(const TermProd& other) { 
    if (&other != this) { 
    delete m_lhs; 
    delete m_rhs; 

    m_lhs = other.m_lhs->clone(); 
    m_rhs = other.m_rhs->clone(); 
    } 
    return *this; 
}; 

爲了校正所有情況下,您還需要添加合適的拷貝構造函數

TermProd::TermProd(const TermProd& other) : 
    m_lhs(other.m_lhs->clone()), 
    m_rhs(other.m_rhs->clone()) 
{ 

} 

真的不過使這個非常簡單的,你應該考慮使用std::shared_ptr<Term>作爲值爲TermPtr。這是一個指針,將使分享工作沒有所有上述開銷

+0

您的分配操作員應檢查您是否分配給自己,並且在此情況下通常不會做任何事情。 – Lindydancer 2012-01-27 16:08:45

+0

@Lindydancer哎呀,很好。更新 – JaredPar 2012-01-27 16:12:08