析构函数中删除的问题

时间:2010-04-02 21:14:40

标签: c++

我写了这段代码 构造函数正常工作,但在析构函数中,我得到“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; 
}

5 个答案:

答案 0 :(得分: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管理。

答案 1 :(得分:7)

你可能会超越mem_ptr数组的末尾。在C和C ++中,指针算法以所涉及的类型为单位,而不是字节。例如,如果您有int *a;,那么如果a为0x100,sizeof(int) == 4,则a + 1为0x104。

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

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

答案 2 :(得分: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) ); 
}

答案 3 :(得分:1)

您正在调用构造函数和析构函数两次,因为您使用的是new-expression和delete-expression:

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

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

如果您只想分配原始内存,可以显式调用operator new:

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

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

答案 4 :(得分: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 ++中为您完成的。