为什么在使用赋值时不为堆栈变量调用析构函数?
Why is the destructor not called for stack variable when using assignement?
这个愚蠢的代码片段已经花了我 2 个小时,我不明白为什么第一个元素的析构函数,即大小为 7 的元素,没有被调用?分配给 new uint16_t[7]
的内存会怎样?
#include <iostream>
using namespace std;
struct Node
{
Node(uint16_t n) : p(new uint16_t[n]) {
cout<<"Constructed with size= "<<n<<", memory addr: "<<(p)<<endl;
for(uint16_t i=0; i<n; i++) p[i] = n;
}
~Node() {
cout<<"Destructor for p[0] = "<< *p <<" with memory addr: "<<p<<endl;
delete[] p;
}
uint16_t *p;
};
int main()
{
{
Node nd1(7);
{
nd1 = Node(3);
cout << "1st place holder" << endl;
}
cout << "2nd place holder" << endl;
}
return 0;
}
输出为
Constructed with size= 7, memory addr: 0x158cc20
Constructed with size= 3, memory addr: 0x158cc40
Destructor for p[0] = 3 with memory addr: 0x158cc40
1st place holder
2nd place holder
Destructor for p[0] = 0 with memory addr: 0x158cc40
*** Error in `./a.out': double free or corruption (fasttop): 0x000000000158cc40 ***
Aborted (core dumped)
I cannot figure out why the destructor of the first element, the one with size 7, not called?
它被调用了。事实上,正是那个析构函数导致程序崩溃。程序的行为是未定义的,因为析构函数删除了先前被临时对象的析构函数删除的相同指针值。并且在此之前它通过那个无效的指针间接。
What happens to the memory allocated for new uint16_t[7]?
当您分配给对象时,指向内存的指针丢失了。这称为内存泄漏。
此代码:nd1 = Node(3);
不是您所期望的。
它不会用Node(3)
替换nd1
并杀死旧的nd1
。
它所做的是创建一个新的临时节点实例 Node(3)
并将每个成员的值复制到 nd1
中。所以 temporary 和 nd1
都包含一个指向相同地址的指针。那时,您泄漏了程序开始时分配的内存 nd1
,因为没有指针指向它,但您没有删除它。
临时死时,nd1
指向死内存。当 nd1
在第二个 }
运行它的析构函数时,它再次删除相同的指针因此你的错误。
要解决此问题,您必须实施所谓的“五法则”或“零法则”。
最简单的是零规则。只需使用 unique_ptr
即可按预期进行销毁:
struct Node
{
Node(uint16_t n) : p(std::make_unique<uint16_t[]>(n)) {
cout<<"Constructed with size= "<<n<<", memory addr: "<<(p)<<endl;
for(uint16_t i=0; i<n; i++) p[i] = n;
}
std::unique_ptr<uint16_t[]> p;
};
int main()
{
{
Node nd1(7);
{
nd1 = Node(3); // assignement destroys the old buffer
cout << "1st place holder" << endl;
}
cout << "2nd place holder" << endl;
}
return 0;
}
这个愚蠢的代码片段已经花了我 2 个小时,我不明白为什么第一个元素的析构函数,即大小为 7 的元素,没有被调用?分配给 new uint16_t[7]
的内存会怎样?
#include <iostream>
using namespace std;
struct Node
{
Node(uint16_t n) : p(new uint16_t[n]) {
cout<<"Constructed with size= "<<n<<", memory addr: "<<(p)<<endl;
for(uint16_t i=0; i<n; i++) p[i] = n;
}
~Node() {
cout<<"Destructor for p[0] = "<< *p <<" with memory addr: "<<p<<endl;
delete[] p;
}
uint16_t *p;
};
int main()
{
{
Node nd1(7);
{
nd1 = Node(3);
cout << "1st place holder" << endl;
}
cout << "2nd place holder" << endl;
}
return 0;
}
输出为
Constructed with size= 7, memory addr: 0x158cc20 Constructed with size= 3, memory addr: 0x158cc40 Destructor for p[0] = 3 with memory addr: 0x158cc40 1st place holder 2nd place holder Destructor for p[0] = 0 with memory addr: 0x158cc40 *** Error in `./a.out': double free or corruption (fasttop): 0x000000000158cc40 *** Aborted (core dumped)
I cannot figure out why the destructor of the first element, the one with size 7, not called?
它被调用了。事实上,正是那个析构函数导致程序崩溃。程序的行为是未定义的,因为析构函数删除了先前被临时对象的析构函数删除的相同指针值。并且在此之前它通过那个无效的指针间接。
What happens to the memory allocated for new uint16_t[7]?
当您分配给对象时,指向内存的指针丢失了。这称为内存泄漏。
此代码:nd1 = Node(3);
不是您所期望的。
它不会用Node(3)
替换nd1
并杀死旧的nd1
。
它所做的是创建一个新的临时节点实例 Node(3)
并将每个成员的值复制到 nd1
中。所以 temporary 和 nd1
都包含一个指向相同地址的指针。那时,您泄漏了程序开始时分配的内存 nd1
,因为没有指针指向它,但您没有删除它。
临时死时,nd1
指向死内存。当 nd1
在第二个 }
运行它的析构函数时,它再次删除相同的指针因此你的错误。
要解决此问题,您必须实施所谓的“五法则”或“零法则”。
最简单的是零规则。只需使用 unique_ptr
即可按预期进行销毁:
struct Node
{
Node(uint16_t n) : p(std::make_unique<uint16_t[]>(n)) {
cout<<"Constructed with size= "<<n<<", memory addr: "<<(p)<<endl;
for(uint16_t i=0; i<n; i++) p[i] = n;
}
std::unique_ptr<uint16_t[]> p;
};
int main()
{
{
Node nd1(7);
{
nd1 = Node(3); // assignement destroys the old buffer
cout << "1st place holder" << endl;
}
cout << "2nd place holder" << endl;
}
return 0;
}