2010-04-02 88 views
4

我写了这段代码。
构造函数正常工作,但在析构函数中,我得到“Windows已经触发了一个断点。”我应该如何纠正这一点?在析构函数中删除的问题

template class CyclicalArray { 
private: 
    T* mem_ptr; 
public: 
    CyclicalArray(size_t capacity, const T& default_value) { 
    this->default_value = default_value; 
    this->capacity = capacity; 
    head_index = 0; 
    mem_ptr = ::new T[capacity]; //memory allocating 
    for(T* p = mem_ptr; p < mem_ptr + capacity * sizeof(T); p += sizeof(T)) { 
     ::new (p) T (default_value); //initialization 
    } 
} 
~CyclicalArray() { 
    for(T* p = mem_ptr + sizeof(T); p < mem_ptr + capacity * sizeof(T); p += sizeof(T)) { 
     p->~T(); 
    } 
    delete[] mem_ptr; 
} 

回答

8

如果您要执行放置新功能,您需要在原始内存上执行此功能。例如:

template class CyclicalArray { 
private: 
    T* mem_ptr; 
public: 
    CyclicalArray(size_t capacity, const T& default_value) { 
    this->default_value = default_value; 
    this->capacity = capacity; 
    head_index = 0; 
    mem_ptr = reinterpret_cast<T*>(::new char[capacity * sizeof(T)]); //memory allocating 
    for(T* p = mem_ptr; p < mem_ptr + capacity; ++p) { 
     ::new (p) T (default_value); //initialization 
    } 
} 
~CyclicalArray() { 
    // this 
    for(T* p = mem_ptr + capacity; p != mem_ptr; --p) { 
     (p-1)->~T(); 
    } 
    delete[] reinterpret_cast<char*>(mem_ptr); 
} 

否则,你会在同一个对象内存中调用T析构函数两次(这不是一件好事)。

此外,由于您的p指针的类型为T*,因此您可以对其执行简单的递增/递减操作 - 编译器会将sizeof(T)问题作为指针算术的正常过程来处理。

最后,严格来说你应该以降序排列数组元素(与构造相反)。

我希望这可以捕获大部分或全部的错误。

你可能真的想考虑使用像std :: vector这样的东西作为商店。下面是一个使用std::vector<>的示例(以及其他一些语法修复)。我不知道,如果你的类将真正需要的default_valuehead_index副本 - 我离开了他们的假设,你打算在其他的方法来使用它们:

#include <vector> 

template <typename T> 
class CyclicalArray { 
private: 
    std::vector<T> backing_store; 
    T default_value; 
    size_t head_index; 

public: 
    CyclicalArray(size_t capacity, const T& def_val) : 
     backing_store(capacity, def_val), 
     default_value(def_val), 
     head_index(0) { 
    } 

    ~CyclicalArray() {} 
}; 

注意如何构造更简单和析构函数是,因为你的头等舱的所有复杂性都由std:vector管理。

7

你可能会超出mem_ptr阵列的末尾。在C和C++中,指针运算以涉及的类型为单位,而不是字节。例如,如果你有int *a;,那么如果a是0x100,并且sizeof(int) == 4,a + 1是0x104。

因此,您将增加p大小的类型的平方,因为加1将移动它sizeof(T)字节,所以增加sizeof(T)它会增加太多。

更不用说您不需要调用数组中的单个析构函数,因为delete []会为您处理这个问题。

1

使用全局函数operator new而不是运算符new。它会分配内存,但不会调用构造函数。同为删除:

template class CyclicalArray { 
private: 
    T* mem_ptr; 
public: 
    CyclicalArray(size_t capacity, const T& default_value) { 
    this->default_value = default_value; 
    this->capacity = capacity; 
    head_index = 0; 
    mem_ptr = static_cast<T*>(::operator new[] (sizeof(T)*capacity)); //memory allocating 
    for(T* p = mem_ptr; p < mem_ptr + capacity; p ++) { 
     ::new (p) T (default_value); //initialization 
    } 
} 
~CyclicalArray() { 
    for(T* p = mem_ptr; p < mem_ptr + capacity; p ++) { 
     p->~T(); 
    } 
    ::operator delete[](static_cast<void*>(mem_ptr)); 
} 
+0

如果我没有弄错,可以使用'std :: allocator '和'allocate(capacity)','construct(p,default_value)','destroy(p)'和'deallocate (mem_ptr,容量)'? – UncleBens 2010-04-02 21:48:55

1

要调用你的构造函数和析构函数两次,因为你正在使用一种新的表达和delete表达式:

// This allocates and calls constructor 
mem_ptr = ::new T[size]; 

// This calls the destructor and deallocates the memory 
delete[] mem_ptr; 

如果你想只分配原始内存,你可以明确地呼叫运营商新的:

// This simply allocates raw memory 
mem_ptr = ::operator new(sizeof(T) * size); 

// And this simply deallocates memory 
::operator delete(mem_ptr); 
1

为什么使用放置新的呢?该代码基本上可以归结为这样:

template <class T> 
class CyclicalArray { 
private: 
    T* mem_ptr; 
    size_t capacity; 
    T default_value; 
    size_t head_index; 
public: 
    CyclicalArray(size_t capacity, const T& default_value) : capacity(capacity), default_value(default_value), head_index(0) { 
     mem_ptr = new T[capacity](default_value); //memory allocating and construction 
    } 

    ~CyclicalArray() { 
     delete[] mem_ptr; 
    } 
}; 

编辑:如果你想使用放置新的,你的循环应该是这样的:

for(T* p = mem_ptr; p != mem_ptr + capacity; ++p) { 

无需通过sizeof(T)规模的东西,这是在C/C++中完成的。