【问题标题】:Can't keep dynamically allocated memory consistent after return返回后无法保持动态分配的内存一致
【发布时间】:2015-12-17 16:33:51
【问题描述】:

我正在开发一个下棋程序。作为其中的一部分,我编写了一个静态方法,该方法应该通过使用各种版本的板子(Piece * board[8][8])调用自身来递归地对其输入进行操作,然后传回std::unique_ptr 中“最佳”版本的板的位置,这是方法的返回类型。

节点定义如下:

class node
{
    public:
    node();
    ~node();
    std::unique_ptr<node> l;
    std::unique_ptr<node> r;
    std::unique_ptr<node> m;
    node * best;
    int bestval;

    Piece * (*board)[8];
};

我们的目标是最终让递归方法的初始调用结果包含一个“最佳”值,该值通过棋盘链接到整个最佳路径选择链。然后我会画出产生的一系列棋盘状态。

作为其中的一部分,必须保留电路板。在每个递归步骤中,无论哪个棋盘“获胜”都会被复制到动态内存中,并且返回的棋盘指针( Piece * (*board)[8]node 声明中) 设置为此动态分配的内存。

这样做是这样的:

    std::unique_ptr<node> ret (new node);
    Piece *** reboard = new Piece**[8];
    for (int i = 0; i < 8; i++)
    {
        reboard[i] = new Piece*[8];
    }
    ...code to copy values to reboard and set other ret property values...
    ret->board = reboard;
    return ret;

然后将获胜棋盘的所有本地值复制到重新棋盘。这一切都很好。如果我在这个阶段将 reboard 的所有值复制到全局板上,返回并将该全局板直接绘制到屏幕上,它会绘制正确的结果。同样,如果我将 ret->board 设置为指向该全局板,然后将值复制到全局板并返回,它会绘制正确的值。

但是,如果我按照上面写的操作并尝试绘制 ret->board,我的绘制方法中会出现无效的内存访问错误,我正在努力尝试来解决这个问题。似乎在返回后立即以某种方式回收了 reboard 指向的内存。在这个应该只是数据的内存中,我看到数组中的条目似乎指向 msctf.dll 中的代码,以及其他无效的数据指针。我认为它正在被垃圾收集回收,所以我什至尝试对我能看到的任何指针进行一些 std::declare_reachable 调用,但这没有帮助。

有人注意到这里发生了什么吗?在我释放它之前,动态分配的内存不应该一直存在吗?

【问题讨论】:

  • 查看位板;它们比您的数据结构更好。此外,国际象棋引擎代码中的堆应该很少。我只在转置表和线程设置期间使用堆分配。上下游戏树不需要堆分配——所有东西都应该预先分配。

标签: c++ memory memory-management recursion garbage-collection


【解决方案1】:

std::unique_ptr 是一个智能指针,它通过指针保留对象的唯一所有权,并在 unique_ptr 超出范围时销毁该对象。没有两个 unique_ptr 实例可以管理同一个对象。

来源:cppreference.com

换句话说,您在点击return 时立即释放内存,然后返回垃圾。当然,尝试取消引用该内存会导致访问冲突。

【讨论】:

  • 对初始递归调用的返回指针有一个全局引用,所有后续调用都保留其被调用者的返回指针,因此唯一指针确实按预期保留。我打算通过说明将 ret->board 指向全局板工作正常来证明这一点。
  • 我再说一遍,简单地说:当ret 超出范围时,内存被释放。如果unique_ptr 的语义不适合您,请停止争论并使用正确的智能指针类。特别是如果您想分享它(并且您愿意),请使用shared_ptr
猜你喜欢
  • 2014-10-23
  • 2021-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
  • 1970-01-01
  • 2017-12-13
  • 1970-01-01
相关资源
最近更新 更多