2010-05-27 267 views
1

我正在寫一個簡單的nD-vector類,但遇到一個奇怪的錯誤。我已經剝離出來的類,以最低限度仍然再現BUG:複製構造函數bug

#include <iostream> 

using namespace std; 

template<unsigned int size> class nvector 
{ 
public: 
    nvector() {data_ = new double[size];} 
    ~nvector() {delete[] data_;} 

    template<unsigned int size2> 
    nvector(const nvector<size2> &other) 
    { 
    data_ = new double[size]; 
    int i=0; 
    for(; i<size && i < size2; i++) 
     data_[i] = other[i]; 

    for(; i<size; i++) 
     data_[i] = 0; 
    } 

    double &operator[](int i) {return data_[i];} 
    const double&operator[](int i) const {return data_[i];} 

private: 
    const nvector<size> &operator=(const nvector<size> &other); //Intentionally unimplemented for now 

    double *data_; 
}; 

int main() 
{ 
    nvector<2> vector2d; 
    vector2d[0] = 1; 
    vector2d[1] = 2; 

    nvector<3> vector3d(vector2d); 
    for(int i=0; i<3; i++) 
    cout << vector3d[i] << " "; 
    cout << endl; //Prints 1 2 0 

    nvector<3> other3d(vector3d); 
    for(int i=0; i<3; i++) 
    cout << other3d[i] << " "; 
    cout << endl; //Prints 1 2 0 
} //Segfault??? 

表面上這似乎做工精細,並且這兩個測試打印出正確的價值觀。但是,在主程序結束時,程序崩潰了一段段錯誤,我找到了nvector的析構函數。

起初我以爲(不正確的)默認賦值運算符被某種方式調用,這就是爲什麼我添加(當前)未實現的顯式賦值運算符來排除這種可能性。

所以我的副本構造函數必須是越野車,但我有一個在那裏我盯着非常簡單的代碼,只是看不到它。你們有什麼想法嗎?

+1

您使用尺寸作爲模板參數的方式讓我非常緊張。 – Uri 2010-05-27 19:17:54

+2

@Uri:這很正常。 :)('std :: array') – GManNickG 2010-05-27 19:22:51

+0

如果在編譯時知道向量的大小,爲什麼動態分配data_? – 2010-05-27 19:24:59

回答

10

轉換構造函數的模板實現永遠不會被視爲複製構造函數的候選函數。您的模板化複製構造函數從不被調用。相反,編譯器使用隱式生成的「默認」複製構造函數實現,該實現執行淺顯複製並帶來明顯的後果。

換句話說,上面實現的模板構造函數永遠不會用作複製構造函數,只能用作轉換構造函數。你必須顯式地將你的copy-constructor實現爲一個非模板函數。

+0

意味着你的分配數組被雙重刪除 - 每個對象指向它一次。 – CuppM 2010-05-27 19:22:57

+0

Doh!這是問題。謝謝! – user168715 2010-05-27 19:35:13

+0

我剛剛注意到了FCD的改變並刪除了我的評論。我的評論僅僅是關於C++ 03和FCD之前的0x草案。顯然他們解決了這個問題:)(刪除12.8/2的腳註,並提供一個更好的例子,12.8/7) – 2010-05-27 21:10:27