从我到目前为止的理解,如果你有一个类对象的向量,如果你擦除向量的任何成员,通常向量将重新分配它的一些对象,以保持内存连续性 . 因此,您需要为擦除矢量成员时要保留的所有内容实现三个规则(析构函数,复制构造函数和复制赋值运算符) .
但是:对于指向类对象的指针向量,结果对我来说不太清楚 . 如果我擦除一个成员,那么C肯定足够聪明,只需复制指针 - 不要疯狂地删除指针(以及它指向的类对象),然后重新创建它和它指向的对象?
如果不是这样,有人可以向我解释这个白痴吗?
向量将单独保留指针值 . 它当然会在你推,弹出或擦除时移动内部数组中的值 .
在这种情况下,值只是指针 . 但是,向量中没有逻辑来确定某些东西是否是指向对象的指针,并在复制值时删除/重新分配它们 .
在包含复杂类型而不是指针的向量的情况下,当然会在重新分配或移动内部数组时尝试复制值 .
该向量将删除,构造和复制它包含的任何类型 . 在指向类/结构的指针向量的情况下,它将删除,构造和复制指针,使指针指向的实际对象单独存在 . 您可以自行分配和取消分配这些内容 .
一个例子:
如果您有以下内容:
class A { A() {} } void foo(void) { A * pointerToA = new A; }
在函数foo的范围的末尾,唯一被解除分配的是变量 pointerToA 本身的内存,即保存地址(32位)的4个字节 - 在这种情况下存储在堆栈中 . 分配给新类A实例的内存的唯一方法是,如果手动调用delete,地址为 pointerToA .
pointerToA
我们以类 A 的数组为例
A
A ** arrayOfPointerToA = new A*[10]; for(unsigned i = 0; i < 10; ++i) arrayOfPointerToA[i] = new A;
这类似于 std::vector<A*> 时发生的情况 . 你打电话的时候
std::vector<A*>
delete [] arrayOfPointerToA;
你要为 array of pointers 释放内存,而不是为每个 A 释放内存 .
在上图中,由上述删除调用解除分配的内存以红色突出显示 . 请注意,在这种情况下,每个 A 都存储在内存中的随机位置,因为它们都是单独分配的 .
现在把它带到一个向量:
std::vector<A> 有效地使用新的 A[size] 来分配内存 . 如果你要存储一个原始指针,这意味着它将分配一个类型为A的数组,这意味着创建了 size 类型为 A 的对象 . 当向量释放其内存 size 时,类型为 A 的对象数被销毁 . 现在采用该示例并用A *替换A,您将看到没有类型A的对象被销毁 .
std::vector<A>
A[size]
size
这是C和指针工作方式的基本部分,而不仅仅是容器的属性 . 如果容器在每个成员上任意调用delete,这就没有意义,因为当我们有一个容器 A 时,我们会在一个对象的实例上调用delete而不是指向该对象的无效指针 .
2 回答
向量将单独保留指针值 . 它当然会在你推,弹出或擦除时移动内部数组中的值 .
在这种情况下,值只是指针 . 但是,向量中没有逻辑来确定某些东西是否是指向对象的指针,并在复制值时删除/重新分配它们 .
在包含复杂类型而不是指针的向量的情况下,当然会在重新分配或移动内部数组时尝试复制值 .
该向量将删除,构造和复制它包含的任何类型 . 在指向类/结构的指针向量的情况下,它将删除,构造和复制指针,使指针指向的实际对象单独存在 . 您可以自行分配和取消分配这些内容 .
编辑
一个例子:
如果您有以下内容:
在函数foo的范围的末尾,唯一被解除分配的是变量
pointerToA
本身的内存,即保存地址(32位)的4个字节 - 在这种情况下存储在堆栈中 . 分配给新类A实例的内存的唯一方法是,如果手动调用delete,地址为pointerToA
.我们以类
A
的数组为例这类似于
std::vector<A*>
时发生的情况 . 你打电话的时候你要为 array of pointers 释放内存,而不是为每个
A
释放内存 .在上图中,由上述删除调用解除分配的内存以红色突出显示 . 请注意,在这种情况下,每个
A
都存储在内存中的随机位置,因为它们都是单独分配的 .现在把它带到一个向量:
std::vector<A>
有效地使用新的A[size]
来分配内存 . 如果你要存储一个原始指针,这意味着它将分配一个类型为A的数组,这意味着创建了size
类型为A
的对象 . 当向量释放其内存size
时,类型为A
的对象数被销毁 . 现在采用该示例并用A *替换A,您将看到没有类型A的对象被销毁 .这是C和指针工作方式的基本部分,而不仅仅是容器的属性 . 如果容器在每个成员上任意调用delete,这就没有意义,因为当我们有一个容器
A
时,我们会在一个对象的实例上调用delete而不是指向该对象的无效指针 .