2012-03-21 38 views
1

我在教自己的c + +模板。我寫了下面的代碼,並且我得到了一個有關正在釋放的指針未被分配的奇怪錯誤。我猜我在我的類模板構造函數中的某個東西實際上並沒有在int上調用new,當我要求這個類的<int>類型時。該代碼正在編譯並自動運行CodeRunner for mac,我設置爲使用clang++編譯器爲c++文件。C++模板代碼導致錯誤,顯然沒有正確分配的對象上調用刪除錯誤

#include <vector> 
#include <iostream> 

template <typename T> 
class HeapVal 
{ 
    public: 
     HeapVal(T val) {ptr = new T(val);} 
     ~HeapVal() {delete ptr;} 
     T get() {return *ptr;} 
    private: 
     T* ptr; 
}; 

int main(){ 
    std::vector< ::HeapVal<int> > vec; 
    for(int i = 0; i < 1000; ++i){ 
    ::HeapVal<int> h(i); 
    vec.push_back(h); 
    } 
    for(int i = 0; i < 1000; ++i){ 
    std::cout << vec[i].get() << std::endl; 
    } 
    return(0); 
} 

該代碼導致在編譯或執行期間出現以下錯誤(在我看來就像是一種運行時類型的錯誤)。

Untitled(30214) malloc: *** error for object 0x7f82f24007c0: pointer being freed was not allocated 
*** set a breakpoint in malloc_error_break to debug 
Run Command: line 1: 30214 Abort trap: 6   ./"$2" "${@:3}" 
+7

這可能很好地解釋你的問題:http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three – chris 2012-03-21 22:32:10

回答

6

您錯過了HeapVal的拷貝構造函數和賦值操作符。這意味着你最終會不止一次嘗試同樣的內存,因爲你有多個指針 - 這就是導致崩潰的原因。

嘗試這樣:

template <typename T> 
class HeapVal 
{ 
public: 
    explicit HeapVal(T val) 
    : ptr(new T(val)) 
    {} 

    ~HeapVal() 
    { 
     delete ptr; 
    } 

    HeapVal(const HeapVal& rhs) 
    : ptr(new T(*rhs.ptr)) 
    {} 

    HeapVal& operator=(const HeapVal& rhs) 
    { 
     HeapVal(rhs).swap(*this); 
     return *this; 
    } 

    T get() const 
    { 
     return *ptr; 
    } 

private: 
    T* ptr; 

    void swap(HeapVal& rhs) 
    { 
     std::swap(ptr, rhs.ptr); 
    } 
}; 
+2

哦,是的,默認的複製構造函數只會使一個指針等於另一個...我想我沒有意識到,當我將某些東西推入std :: vector時,將會創建副本。 – 2012-03-21 23:09:06

+0

@ JohnSt.John:當你將一個對象傳遞給'std :: vector.push_back'時,'std :: vector'會將該對象複製到它的緩衝區中。如果需要調整緩衝區的大小,那麼它會將舊緩衝區中的所有項目複製到新的更大的緩衝區中。 – 2018-01-18 02:12:56

2

任何時候,HeapVal被複制(或轉讓,對於這個問題),你有兩個HeapVal對象,既包含指向同一個地方結束。當第一個被破壞時,它會刪除指向的對象。當第二個被破壞時,它會嘗試再次刪除同一個對象 - 導致未定義的行爲。

就你而言,你足夠幸運,運行時庫檢測到並報告了問題。

谷歌搜索「三巨頭的C++法」或類似的應該會產生相當多的關於這個問題的討論。

2

問題是,當你推HeapVal對象,你最終做一個ptr的淺拷貝,所以這很容易出現雙刪除。

您需要重寫默認的複製構造函數和賦值運算符,或者您可以使用智能指針而不是原始ptr。 Boost::shared_ptr也許在你的情況下是一種矯枉過正,但它的好東西很好學。