在c ++向量中手动执行内存重新分配

时间:2015-07-05 05:19:03

标签: c++ memory vector

From this link,它说使用c ++向量时有四个步骤进行内存重新分配......

  1. 为所需的新容量分配足够的内存;
  2. 将元素从旧内存复制到新内存;
  3. 销毁旧记忆中的元素;
  4. 并释放旧记忆。
  5. 我对数字3和4特别感兴趣,是否可以通过代码执行这些任务?或者它只是在后台发生。

    即,我能够"消灭记忆中的元素"通过C ++中的代码?我能直接"释放内存"用C ++代码?

4 个答案:

答案 0 :(得分:2)

是的,是的!您可能希望查看operator new类型,或新展示位置,operator delete,析构函数调用和{{1}}。 (请注意,operator new和operator delete是分配和释放函数的名称,与new和delete运算符不同。)

希望这有帮助!

答案 1 :(得分:1)

  

我能通过C ++中的代码“破坏内存中的元素吗?”

是。通过调用对象的析构函数。例如,如果void test() { Foo.foo((Value<Boolean> value) -> true).booleanValue(); } 是对x类型对象的引用,则可以使用以下命令销毁该对象:

T
  

我能否在C ++代码中直接“释放内存”?

当然。存在各种解除分配功能,其具有相应的分配功能。如果您使用x.~T(); 分配,则会使用malloc取消分配。如果您使用free分配,则会使用operator new()取消分配。如果您使用operator delete()分配,则会使用new char[]解除分配。

答案 2 :(得分:1)

您可以使用简单的STL函数..

  • 您可以使用vector::erase成员函数从向量中移除单个元素或一系列元素,

    iterator erase (const_iterator position);
    iterator erase (const_iterator first, const_iterator last); 
    
  • 然后,在C ++ 11下,调用vector::shrink_to_fit来请求容器将其容量减少到当前大小。 (请注意,实现可以自由地忽略此请求。)

        void shrink_to_fit();
    

    或使用vector::resize

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

类似于:

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

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

*如果你调整到比实际尺寸更小的尺寸 - 假设你的矢量有10个元素,你调整大小为size_t = 7,之后你的矢量将只有前7个元素,其余的将是破坏。

此外,如果您只想销毁某些特定元素,则可以使用Erase-remove idiom - https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom,然后使用shrink_to_fit()resize()

答案 3 :(得分:0)

是的,在C ++中销毁和取消分配数据都是可能的,甚至是必需的。

通常,C ++中有两个可能存在数据的地方:

  1. 自动管理的堆栈,
  2. 堆,您负责删除不再需要的数据。
  3.  void fn(void) {
       Data data;
     }
    

    在上面的函数中,只要调用该函数,就会在堆栈中为变量数据保留一些空间。然后它的构造函数将被调用,它可以进行额外的设置(你可以自己编写它们并做任何事情)。在函数返回时,首先在通过移动堆栈指针释放堆栈上占用的空间之前调用析构函数(您也可以并且有时必须自己实现)。所有这一切都是自动发生的。

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

    在此函数中,与上面相同,仅使用指针,您可以将其视为描述内存中某个位置的整数。 (并且只在理论上,因为像这样的指针没有构造函数或析构函数)

    但是还有第二行和第三行:这里我在堆中分配和构造一个Data实例,并在之后销毁并释放它。但我不必在那里做。我可以存储指针,并在函数返回很久之后使用它来稍后访问实例。

    所有这些都包含在像vector这样的类中,以提供与托管语言相同的便利性,只有在需要时才能使用它,并且不会被迫使用它。

    例如,这是一个玩具载体,仅显示资源管理的一部分:

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

    再说一遍:这是玩具代码,你说明了一般的想法,对于真正的代码,还有更多需要考虑。

    作为最后一点:上面释放内存和破坏总是一起执行。这几乎是每次你需要的。但您也可以手动调用析构函数:

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

    分配和构造实例也是如此。有一些内存可以使用placement new来调用构造函数。

    此外,构造函数和析构函数不仅仅是关于管理内存,它们还可以帮助打开文件,当前播放音乐或者几乎所有需要初始化和完成的内容。

    我希望这个快速而粗略的旅程可以帮助您理解基本概念。我遗漏了很多东西,并且在某些方面并不准确,所以仅将其作为进一步研究的基础