emplace_back和push_back给出错误'double free or corruption (fasttop)'尽管定义了复制和移动构造函数
emplace_back and push_back give 'double free or corruption (fasttop)' error although copy and move constructor are defined
我只是在使用C++,可能在这里遗漏了一些明显的东西。我有一个动态分配数组的类,我想把它的对象放入向量中。由于数组必须在析构函数中释放,并且它是由vector.push_back()
调用的,因此我必须定义一个复制和移动构造函数,以避免内存损坏错误。但是,下面的示例仍然给我一个double free or corruption (fasttop)
错误。
#include <iostream>
#include <vector>
using namespace std;
class bla {
public:
int* arr;
bla() {
arr = new int[10];
for (size_t i = 0; i < 10; i++) {
arr[i] = 42;
}
}
bla(bla&& b) : arr(b.arr) {
cout << "move" << endl;
}
bla(const bla& b) : arr(b.arr) {
cout << "copy" << endl;
}
~bla() {
cout << "delete" << endl;
delete[] arr;
}
};
int main() {
vector<bla> blas;
blas.reserve(5000);
blas.push_back(bla()); // same result with emplace_back
blas.push_back(bla()); // same result with emplace_back
blas.push_back(bla()); // same result with emplace_back
return 0;
}
有人能解释我做错了什么吗?也许还有人能提供一个例子,说明如何将具有动态内存的对象添加到向量中(我知道我可以使用指针,但从我读到的内容来看,它也应该适用于对象本身(。
我用-Wall -std=c++11 -lm
运行g++ (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
UPDATE 1:在g++ 7.4.0
上使用相同的标志运行相同的代码不会导致双空闲错误。有人知道为什么吗?
UPDATE 2:对于子孙后代来说,因为显然没有那么多针对浮动的动态数组实现5规则的最小示例。这就是你应该做的(如果我错了,请纠正我(:
#include <iostream>
#include <vector>
using namespace std;
class bla {
public:
int* arr;
bla()
: arr(nullptr)
{
arr = new int[10];
for (size_t i = 0; i < 10; i++) {
arr[i] = 42;
}
}
~bla() {
cout << "delete" << endl;
delete[] arr;
}
// deep copy constructor
bla(const bla& other) {
cout << "copy" << endl;
arr = new int[10];
for (size_t i = 0; i < 10; i++) {
arr[i] = other.arr[i];
}
}
// deep copy assignment
bla& operator = (const bla& other) {
cout << "copy assignment" << endl;
if (&other != this) {
delete[] arr;
arr = new int[10];
for (size_t i = 0; i < 10; i++) {
arr[i] = other.arr[i];
}
}
return *this;
}
// move constructor
bla(bla&& other)
: arr(other.arr) {
cout << "move" << endl;
other.arr = nullptr;
}
// move assignment
bla& operator = (bla&& other){
cout << "move assignment" << endl;
if(&other != this) {
delete[] arr;
arr = other.arr;
other.arr = nullptr;
}
return *this;
}
};
int main() {
vector<bla> blas;
cout << "=========nstart pushsn=========" << endl;
blas.push_back(bla());
blas.push_back(bla());
blas.push_back(bla());
cout << endl << "=========nend pushsn=========" << endl << endl;;
cout << "for each:" << endl;
for (bla b : blas) {
cout << b.arr[0] << endl;
}
cout << endl;
cout << "native for:" << endl;
for (size_t i = 0; i < 3; i++) {
cout << blas[i].arr[0] << endl;
}
return 0;
}
我读到我必须定义一个副本,并将构造函数移动到避免内存损坏错误。
这是真的,但他们也需要做正确的事情。不仅仅是任何复制/移动构造函数都能完成这项工作;这里的复制构造函数和移动构造函数都有相同的缺陷。以复制构造函数为例:
bla(const bla& b) : arr(b.arr) {
因此,如果你用一张纸和一支铅笔计算出这里发生了什么,在复制构造发生后,新对象和原始对象b
都将具有相同的arr
指针。因为这正是这个代码的作用。
因此,当两个对象都被销毁时,它们的析构函数将尝试delete[]
相同的精确指针。CCD_ 9和同一对象都具有相同的CCD_。这是你的双人间。
move构造函数也会出现同样的问题。
此外,显示的类没有显式赋值或移动赋值运算符。因此,将其中一个对象分配给另一个对象将:1(最终泄露被覆盖对象的arr
,2(最终导致两个对象具有相同的arr
,并且当它们最终被销毁时会出现相同的问题。
在复制构造函数的情况下,除了复制从arr
复制的及其值之外,您没有其他选择。在移动构造函数的情况下,您可以选择仅将b.arr
设置为nullptr
。然后,析构函数将悄悄地忽略CCD_ 17的CCD_ 16离子;尽管通常认为在delete[]
使用它之前显式检查nullptr
是一种很好的做法
您还需要实现适当的operator=
重载(只是一个带有可选移动分配的常规分配(,以解决相同的问题。
- 在提升multi_index容器中,是否定义了"default index"?
- #定义c-预处理器常量..我做错了什么
- 用C++中的一个变量定义一个常量
- 部分定义/别名模板模板参数
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- #为""定义宏;静态";针对不同的上下文
- 如何确保C++函数在定义之前声明(如override关键字)
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在命名空间中定义函数还是限定函数
- 此代码是否违反一个定义规则
- 编译C++时未定义的引用
- 不同翻译单元中不可重载的非内联函数定义
- 为什么在定义函数之前先声明它
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 使用用户定义函数的字符串反转
- 用户定义函数中的指针和输入
- vscode g++链路故障:体系结构x86_64的未定义符号
- vector.push_back(vector.back()+1) 是未定义的行为吗?