Destruction removal issues

I wrote this code.
The constructor works fine, but in the destructor I get "Windows called a breakpoint." How do I fix this?

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; } 
+4
source share
5 answers

If you intend to perform a new placement, you need to do this in raw memory. Sort of:

 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); } 

Otherwise, you will call the T destructor twice in the same memory of the object (not very good).

In addition, since your p pointers are of type T* , you can perform simple increments / reductions on it - the compiler will treat the sizeof(T) problem as a regular pointer arithmetic course.

Finally, strictly speaking, you must destroy the elements of the array in descending order (the opposite of construction).

I hope this catches most or all of the bugs.

You might want to use something like std :: vector as storage. An example using std::vector<> follows (with several other syntax fixes). I'm not sure if your class really needs a copy of default_value or head_index - I left them under the assumption that you plan to use them in other methods:

 #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() {} }; 

Note how much easier the constructor and destructor are, since all the complexity of your first class is controlled by std:vector .

+8
source

You are probably going to go beyond the mem_ptr array. In C and C ++, pointer arithmetic is in units of the type used, not in bytes. For example, if you have int *a; , then if a is 0x100, and sizeof(int) == 4 , a + 1 is 0x104.

Therefore, you increase p by the size of the type square, since adding 1 to it will move its sizeof(T) bytes, and therefore adding sizeof(T) to it will increase it too much.

Not to mention that you do not need to call separate destructors in the array, since delete [] will take care of this for you.

+7
source

Use the global operator new function instead of the new operator. It will allocate memory, but will not call constructors. The same goes for delete:

 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) ); } 
+1
source

You call your constructors and destructors twice because you are using the new expression and the delete expression:

 // This allocates and calls constructor mem_ptr = ::new T[size]; // This calls the destructor and deallocates the memory delete[] mem_ptr; 

If you just want to allocate raw memory, you can explicitly call the new operator:

 // This simply allocates raw memory mem_ptr = ::operator new(sizeof(T) * size); // And this simply deallocates memory ::operator delete(mem_ptr); 
+1
source

Why use a new placement? This code basically boils down to the following:

 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; } }; 

EDIT: If you want to use a new placement, your loop should look like this:

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

No need to scale objects on sizeof(T) , which is done for you in C / C ++.

+1
source

Source: https://habr.com/ru/post/1305889/


All Articles