Manually doing memory reallocation in C ++ vectors

From this link it says that when using C ++ vectors there are four steps to reallocate memory ...

  • Allocate enough memory for the desired new capacity;
  • Copy items from old memory to new;
  • Destroy items in old memory;
  • and Deallocate old memory.

I'm especially interested in the numbers 3 and 4, is it possible to accomplish these tasks with code? Or it just happens in the background.

Ie Can I "destroy items in memory" with C ++ code? And can I directly "free memory" in C ++ code?

+3


source to share


4 answers


Can I "destroy items in memory" via C ++ code?

Yes. Calling the object's destructor. For example, if x

is a reference to an object of type T

, you can destroy that object with:

x.~T();

      



And can I directly "free memory" in C ++ code?

Sure. There are many release functions that come with associated distribution functions. If you have allocated malloc

, you will release it with free

. If you have allocated operator new()

, you will release it with operator delete()

. If you have allocated new char[]

, you will release it with delete[]

.

+1


source


Yes and yes! You might want to explore either the type std::allocator

or add new operator new

,, destructor calls, and operator delete

. (Note that operator new and operator delete are allocation and deallocation function names, not the same as new and delete operators).



Hope this helps!

+2


source


You can use simple STL functions for this.

  • you can use a member function vector::erase

    to remove a single element or a range of elements from your vector,

    iterator erase (const_iterator position);
    iterator erase (const_iterator first, const_iterator last); 
    
          

  • and then under C ++ 11 call vector::shrink_to_fit

    to request the container to reduce its capacity to its current size. (Note that the implementation may ignore this request though ..)

        void shrink_to_fit();
    
          

    or use vector::resize

    void resize (size_type n);
    void resize (size_type n, const value_type& val);
    
          

For something like:

myVector.erase(myVector.begin(), myVector.begin() + 3);
myVector.shrink_to_fit();

      

Or

myVector.erase(myVector.begin(), myVector.begin() + 3);
resize(myVector.size()); 

      

* If you resize to a smaller size than the actual one, let's say your vector has 10 elements and you resize to size_t = 7, after that your vector will only have the first 7 elements, the rest will be destroyed.

Also, if you only want to destroy some specific items, you can use Erase-remove idiom

- https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom and then shrink_to_fit()

or resize()

.

+1


source


Yes, it is possible and even required for destroying and freeing data in C ++.

Generally, there are two possible places where data can be found in C ++:

  • A stack that is automatically managed and
  • a heap where you are responsible for deleting data that is no longer needed.

...

 void fn(void) {
   Data data;
 }

      

In a function like above, as soon as the function is called, some space will be reserved in the variable for variable data. Then the constructor will be called, which can do additional customization (you can write them yourself and do literally everything). The first time the function returns, the destructor (which you can and sometimes must do yourself) is called before the space occupied on the stack is freed by moving the stack pointer. All this happens automatically.

void fn2(void) {
  Data * dataptr;
  dataptr = new Data();
  delete dataptr;
}

      

This function does the same thing as above, only with a pointer, which you can think of as an integer describing some location in memory. (And only in theory, since such pointers have no constructor or destructor)

But then there are also the second and third lines: Here I allocate and instantiate the Data on the heap and then destroy and free it immediately. But I shouldn't be doing it right there. I could save the pointer and use it for later access to the instance after the function has returned.

All of this is wrapped inside classes like vector to provide the same usability as in managed languages, only that you can only use it when you need it and you don't have to use it.

As an example, here is a toy vector showing only part of resource management:

struct vec {
  size_t size;
  int * values;
  vec() {
    // constructor, may do anything here
    size = 0;
    values = nullptr;
  }
  free() {
    if (values != nullptr) {
      delete [] values;
    }
  }
  void push_back(int v) {
    // allocating new memory
    int * newvalues = new int[size + 1];
    // copy existing values
    for (size_t it = 0; it < size; ++it) {
      newvalues[it] = values[it];
    }
    // delete original values
    free ();
    // add new value at the now free spot
    newvalues[size] = v;
    ++size;
    // update the pointer to point to the new memory
    values = newvalues;
  }
  ~vec() {
    // destructor, may do anything here
    free();
  }
};

      

Just to say it again: this is toy code illustrating the general idea, for real code there is a lot more to consider.

As a final note: The above memory deallocation and destruction have always been done together. This is almost every time you need it. But you can also call the destructor manually:

Data data;
// ...
data.~Data();

      

The same applies to distribution and instantiation. With memory, you can use the new location to call the constructor.

In addition, constructors and destructors not only deal with memory management, but can also help with open files, currently playing music, or just about anything else that needs initialization and finalization.

I hope this quick and rough tour helps you understand the basic concept. I left out a lot of things and was not accurate at some points, so only use this as a basis for further research.

0


source







All Articles