英文:
Destructor is not being invoked
问题
我已经编写了以下代码来实现一个堆栈。
#include <iostream>
using namespace std;
class stack
{
public:
int *top;
int size, capacity;
stack(int c) : capacity(c)
{
size = 0;
top = new int[capacity];
capacity = capacity - 1;
}
~stack() // 在程序结束时删除堆栈
{
delete[] top;
top = NULL;
cout << "删除堆栈" << endl;
}
void push(int data)
{
// 堆栈是否已满
if (is_stackFull())
{
cout << "堆栈已满" << endl;
return;
}
// 填充数据
*top = data;
// 更新堆栈变量
top += 1;
size += 1;
return;
}
void pop()
{
// 堆栈是否为空
if (is_stackEmpty())
{
cout << "堆栈为空" << endl;
return;
}
// 更新堆栈变量
top -= 1;
size -= 1;
return;
}
bool is_stackFull()
{
return (size == capacity);
}
bool is_stackEmpty()
{
return (size == 0);
}
};
int main()
{
stack s(10);
s.push(15);
//s.pop(); // 当我注释掉这行代码时,输出会发生什么变化?
return 0;
}
在这段代码中,当我注释掉s.pop()
方法时,析构函数没有被调用。
有人能解释这种行为背后的技术原因吗?
我尝试理解如何在C++类中调用析构函数。
英文:
I have written the following code to implement a stack.
#include<iostream>
using namespace std;
class stack
{
public:
int *top;
int size, capacity;
stack(int c):capacity(c){
size = 0;
top = new int[capacity];
capacity = capacity - 1;
}
~stack() // deleting the stack at the end of program
{
delete[] top;
top = NULL;
cout << "deleted the stack" << endl;
}
void push(int data)
{
// Is there is a space
if(is_stackFull())
{
cout << "stack is full" << endl;
return;
}
// populate the data
*top = data;
// updating the stack variables
top += 1;
size += 1;
return;
}
void pop()
{
// is stack empty
if(is_stackEmpty())
{
cout << "stack is empty" << endl;
return;
}
// update the stack variables
top -= 1;
size -= 1;
return;
}
bool is_stackFull()
{
return (size == capacity);
}
bool is_stackEmpty()
{
return (size == 0);
}
};
int main()
{
stack s(10);
s.push(15);
//s.pop(); // what happens to the output when i comment out this code?
return 0;
}
In the code, the destructor is not being invoked when I commented the s.pop() method.
Can any one explain the tech reason behind such behavior?
I tried understanding the ways to invoke the destructor in a C++ class.
答案1
得分: 4
在stack::push
中,您正在更改top
指向的内容。因此,它不能再被删除。如果您推送一次并弹出一次,top
将回到之前的状态,错误就不会发生。
与其修改top
指针,您可以跟踪一个顶部_索引_并进行修改。例如。
#include <iostream>
#include <algorithm>
#include <optional>
template <class T>
class Stack {
public:
using size_type = std::size_t;
// 构造函数
Stack(size_type cap)
: capacity(cap), top(0), data(new T[cap])
{ }
// 析构函数
~Stack() {
delete[] data;
}
// 拷贝构造函数
Stack(const Stack& s)
: capacity(s.capacity), top(s.top), data(new T[s.capacity])
{
std::copy(s.data, s.data + capacity, data);
}
// 拷贝赋值
Stack& operator=(const Stack& s) {
top = s.top;
capacity = s.capacity;
delete[] data;
data = new T[capacity];
std::copy(s.data, s.data + capacity, data);
return *this;
}
// 移动构造函数
Stack(Stack&& s)
: capacity(s.capacity), top(s.top), data(s.data)
{
s.capacity = 0;
s.top = 0;
s.data = nullptr;
}
size_type get_capacity() const { return capacity; }
size_type get_top() const { return top; }
bool is_empty() const { return top == 0; }
bool is_full() const { return top == capacity; }
bool push(T val) {
if (is_full()) return false;
data[top++] = val;
return true;
}
std::optional<T> pop() {
if (is_empty()) return std::nullopt;
return std::optional<T>{data[--top]};
}
private:
T* data;
size_type top;
size_type capacity;
};
int main() {
auto s = Stack<int>(10);
s.push(19);
s.push(67);
std::cout << s.pop().value() << " "
<< s.pop().value() << std::endl;
}
英文:
In stack::push
you are changing what top
points to. Thus it can no longer be deleted. If you push once and pop once, top
goes back to what it was, and the error does not occur.
Rather than modifying the top
pointer, you can keep track of a top index and modify that. E.g.
#include <iostream>
#include <algorithm>
#include <optional>
template <class T>
class Stack {
public:
using size_type = std::size_t;
// Constructor
Stack(size_type cap)
: capacity(cap), top(0), data(new T[cap])
{ }
// Destructor
~Stack() {
delete[] data;
}
// Copy constructor
Stack(const Stack& s)
: capacity(s.capacity), top(s.top), data(new T[s.capacity])
{
std::copy(s.data, s.data+capacity, data);
}
// Copy assignment
Stack& operator=(const Stack& s) {
top = s.top;
capacity = s.capacity;
delete[] data;
data = new T[capacity];
std::copy(s.data, s.data+capacity, data);
return *this;
}
// Move constructor
Stack(Stack&& s)
: capacity(s.capacity), top(s.top), data(s.data)
{
s.capacity = 0;
s.top = 0;
s.data = nullptr;
}
size_type get_capacity() const { return capacity; }
size_type get_top() const { return top; }
bool is_empty() const { return top == 0; }
bool is_full() const { return top == capacity; }
bool push(T val) {
if (is_full()) return false;
data[top++] = val;
return true;
}
std::optional<T> pop() {
if (is_empty()) return std::nullopt;
return std::optional<T>{data[--top]};
}
private:
T *data;
size_type top;
size_type capacity;
};
int main() {
auto s = Stack<int>(10);
s.push(19);
s.push(67);
std::cout << s.pop().value() << " "
<< s.pop().value() << std::endl;
}
答案2
得分: 3
析构函数确实被调用了,只是没有按照你的预期执行。当你调用 push
但没有调用 pop
时,top
最终指向了比起始位置右边一个位置。因此,析构函数最终调用 delete
时的地址与 new
返回的地址不同,这属于未定义行为。这意味着你的代码基本上可以随意执行,而在这种情况下显然没有打印出 "deleted the stack" 消息。当我运行它时,出现如下错误:
free(): invalid pointer
Aborted (core dumped)
要修复它,你可以在调用 delete
之前在析构函数中添加一行 top -= size
,这样它就会指向与开始相同的位置。
英文:
The destructor is being invoked, it's just not doing what you expect. When you call push
but not pop
, top
ends up pointing one space to the right of where it started. So, the destructor ends up calling delete
on a different address from the one returned by new
, which is undefined behavior. That means your code can basically do whatever it wants, which in this case apparently means not printing your deleted the stack
message. When I run it, I get
free(): invalid pointer
Aborted (core dumped)
To fix it, you could add a line top -= size
to your destructor before you call delete
so that it is pointing to the same place it started.
答案3
得分: 1
析构函数实际上被调用了,但它没有到达cout << "deleted the stack" << endl;
那一行。当你delete[] top
时失败了。为什么?因为top
不是一个有效的指针。相反,top
指向了在构造函数期间分配的有效指针+4。所以,想象一下,在创建栈时,你的top
是0x004
,在使用s.push(15)
推送一个值之后,它变成了0x008
(假设int是4个字节长),当你尝试删除它时,你尝试删除的是0x008
,这不是一个有效的分配内存地址,有效的地址是0x004
。因此,在打印deleted the stack
之前,你的程序退出了,因为你尝试释放一个无效的地址。
英文:
The descructor is actually called, but it doesn't reach the cout << "deleted the stack" << endl;
line. It failed when you delete[] top
. Why? Because top
is not a valid pointer. Rather, the top
is pointing into the valid pointer you allocated during constructor + 4. So, imagine your top
when creating the stack was 0x004
, after you push a value using s.push(15)
, it becomes 0x008
(assuming int is 4 bytes long), and when you tried to delete it, you tried to delete 0x008
which is not a valid allocated memory address, the valid one is 0x004
. Thus, your program exit before it prints the deleted the stack
because you tried to free an invalid address.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论