std :: vector内存处理

Aru*_*rup 22 c++ vector

我试图谷歌搜索我的问题的答案,但我找不到任何有效的解释,因此我在这里发布我的问题.以下是我的示例代码和输出:

#include <iostream>
#include "vector"
using namespace std;

typedef struct Node{
    int data;
    Node(){
        data = 0;
        std::cout << "Node created. " << this <<'\n';
    }
    ~Node(){
        data = 0;
        std::cout << "Node destroyed. " << this <<'\n';
    }
} Node;

int main() {
    std::vector<Node> vec;
    for(int i = 0; i < 2 ; i++)
       vec.push_back( *(new Node));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Node created. 0x9e0da10
Node created. 0x9e0da30
Node destroyed. 0x9e0da20
Node destroyed. 0x9e0da40
Node destroyed. 0x9e0da44
Run Code Online (Sandbox Code Playgroud)

为什么会有一个额外的破坏以及为什么创建的对象与被破坏的对象不同?

eml*_*lai 39

vec.push_back( *(new Node)); 是一个直接的内存泄漏.

首先,动态分配a Node,然后复制Node到向量中.复制操作是创建新对象的原因,这就是为什么this不同的原因.

原始(动态分配)Node永远不会被释放,但副本是在向量的析构函数运行时(即在函数结束时).

为什么三个析构函数调用而不是两个?这是由你自动重新分配矢量引起的push_back.它将其元素移动/复制到新的内存位置,从而破坏旧元素.


请注意,通常,当您只需要一个n默认构造元素的向量时,您可以:

std::vector<Node> vec(2);
Run Code Online (Sandbox Code Playgroud)

这就要求Node()对元素(默认构造函数)vec[0]vec[1],你不需要一个循环(或动态分配).


Vad*_*Key 18

如果你要添加一个拷贝构造函数,你会找到答案:

Node created. 0x60200000df90
Node copied: 0x60200000df70  Source: 0x60200000df90
Node created. 0x60200000df50
Node copied: 0x60200000df34  Source: 0x60200000df50
Node copied: 0x60200000df30  Source: 0x60200000df70
Node destroyed. 0x60200000df70
Node destroyed. 0x60200000df34
Node destroyed. 0x60200000df30
Run Code Online (Sandbox Code Playgroud)

因此,当您向向量添加第二个元素时,将没有足够的容量,向量必须调整存储大小并将所有旧元素(在这种情况下只有一个这样的元素)复制到新空间.这就是为什么要调用一个额外的复制构造函数的原因.

是的,在C++中,所有标准容器都要求对象应该复制或移动构造,因此您不必在堆上创建它们(如在Java中).代码越正确如下:

#include <iostream>
#include "vector"


struct Node {
  int data;
  Node() : data(0) {
    std::cout << "Node created. " << this <<'\n';
  }

  Node(const Node &n) : data(n.data) {
    std::cout << "Node copied: " << this << "  Source: " << &n << std::endl;
  }

  ~Node(){
    // You don't need data = 0 in destructor
    std::cout << "Node destroyed. " << this <<'\n';
  }

};

int main() {
  std::vector<Node> vec;
  for(int i = 0; i < 2 ; i++) {
    vec.push_back(Node());
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)


Lou*_*uen 12

向向量添加元素时,可以通过复制构造函数(或移动构造函数)构造新副本.

所以一条线就像vec.push_back( *(new Node));做两件事.

  • 它构造了一个动态分配的新节点new.
  • 它将新节点复制到向量中.这意味着通过复制构造函数创建了一个新节点.
  • 原始节点永远不会被释放(这称为内存泄漏)

这个版本的代码与复制构造函数可能会为您提供一些见解:http://ideone.com/ow5YOI