析构函数未被调用。

huangapple go评论90阅读模式
英文:

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&lt;iostream&gt;
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 &lt;&lt; &quot;deleted the stack&quot; &lt;&lt; endl;
	}
	
	void push(int data)
	{
		// Is there is a space
		if(is_stackFull())
		{
			cout &lt;&lt; &quot;stack is full&quot; &lt;&lt; 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 &lt;&lt; &quot;stack is empty&quot; &lt;&lt; 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 &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;optional&gt;

template &lt;class T&gt;
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&amp; s)
        : capacity(s.capacity), top(s.top), data(new T[s.capacity])
    {
        std::copy(s.data, s.data + capacity, data);
    }

    // 拷贝赋值
    Stack&amp; operator=(const Stack&amp; 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&amp;&amp; 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&lt;T&gt; pop() {
        if (is_empty()) return std::nullopt;

        return std::optional&lt;T&gt;{data[--top]};
    }

private:
    T* data;
    size_type top;
    size_type capacity;
};

int main() {
    auto s = Stack&lt;int&gt;(10);

    s.push(19);
    s.push(67);

    std::cout &lt;&lt; s.pop().value() &lt;&lt; &quot; &quot;
              &lt;&lt; s.pop().value() &lt;&lt; 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 &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;optional&gt;

template &lt;class T&gt;
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&amp; s)
    : capacity(s.capacity), top(s.top), data(new T[s.capacity])
    {
        std::copy(s.data, s.data+capacity, data);
    }

    // Copy assignment
    Stack&amp; operator=(const Stack&amp; 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&amp;&amp; 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&lt;T&gt; pop() {
        if (is_empty()) return std::nullopt;

        return std::optional&lt;T&gt;{data[--top]};
    }

    private:
    T *data;
    size_type top;
    size_type capacity;
};

int main() {
    auto s = Stack&lt;int&gt;(10);

    s.push(19);
    s.push(67);

    std::cout &lt;&lt; s.pop().value() &lt;&lt; &quot; &quot;
              &lt;&lt; s.pop().value() &lt;&lt; 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。所以,想象一下,在创建栈时,你的top0x004,在使用s.push(15)推送一个值之后,它变成了0x008(假设int是4个字节长),当你尝试删除它时,你尝试删除的是0x008,这不是一个有效的分配内存地址,有效的地址是0x004。因此,在打印deleted the stack之前,你的程序退出了,因为你尝试释放一个无效的地址。

英文:

The descructor is actually called, but it doesn't reach the cout &lt;&lt; &quot;deleted the stack&quot; &lt;&lt; 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.

huangapple
  • 本文由 发表于 2023年7月20日 11:49:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76726552.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定