【问题标题】:Access Violation in unique_ptr listunique_ptr 列表中的访问冲突
【发布时间】:2014-06-14 23:12:18
【问题描述】:

我有一个 listunique-ptrs,在清除列表后,会出现以下错误:

Unhandled exception at 0x013EA350 in Last.exe: 0xC0000005: Access violation reading location 0xFEEEFEEE.

当迭代元素时,这在 std::list 文件中触发。这个问题有点独特:

  1. MenuManager 有一个 unique_ptr<Menu> 对象列表。
  2. Menu 有一个 unique_ptr<MenuItem> 对象列表。
  3. 第一个Menu 及其所有MenuItems 完美破坏,但是在清除MenuManager 列表中的第二个Menu 时触发此错误,与完全独立的MenuItems。看起来第二个unique_ptr<Menu> 在第一个销毁后变得未定义,尽管它在MenuManager 的销毁开始时存在且非空。

这是什么原因造成的? (具体来说,不是我的代码在哪里导致了这个错误。我想知道这可能是什么原因)

MenuManager.h

class MenuManager
{
public:
    /*MenuManager(list<Menu*> menus) 
        : m_menus(menus) { SetMenu( menus.front() ); }*/
    MenuManager() : m_currentMenu(nullptr) {}


    // Get the menu that the manager is pointing to.
    Menu* GetCurrentMenu(void) { return m_currentMenu; }

    // Set the current menu based on its name.
    void SetMenu(string menuName) { SetMenu( GetMenuByName(menuName) ); }
    // Add a menu to the list of menus managed by this object.
    void AddMenu(Menu* menu);

    // Render the current menu.
    void RenderMenu(void) { m_currentMenu->Render(); }

private:
    list< unique_ptr<Menu> > m_menus; // The list of menus managed by this object
    Menu* m_currentMenu; // A pointer to the menu in current use

    Menu* GetMenuByName(string menuName);
    void SetMenu(Menu* menu); // Set the menu based on the menu argument
};

Menu 是另一个基本上不相关的类的子类。但是,它的列表定义为list&lt; unique_ptr&lt;MenuItem&gt; &gt;MenuItem 的定义无关紧要。

【问题讨论】:

  • 请出示代码。听起来您描述的代码中存在错误。
  • 请贴出MenuMenuItem的定义
  • 好的,会的。虽然真的没有比这更多的了。
  • 很公平,在这个问题上 +1 可以抵消其他人的不耐烦。您发布的大部分内容都是声明,而不是定义。如果您可以将此问题缩小到足以发布的小问题(但它是一个独立的可编译程序),但仍然表现出症状,我相信我们可以诊断它。
  • 0xFEEEFEEE 表示内存已被释放。 stackoverflow.com/questions/127386/…

标签: c++ list c++11 unique-ptr


【解决方案1】:

您没有显示足够多的代码来查明错误,但错误说明了一切......

Last.exe 中 0x013EA350 处未处理的异常:0xC0000005: 访问冲突读取位置 0xFEEEFEEE。

在 Visual Studio 下的调试模式下,被释放的内存设置为代码 0xFEEE。所以指针被释放了两次。

请注意,我看到管理器有一个 std::list 指针,它实际上并没有管理:你有一个带有裸指针的 AddMenu()

我强烈建议您在任何地方都将std::unique_ptr 替换为std::shared_ptr,并且永远不要在任何地方使用裸指针(除非调用需要此类裸指针的较低级别的API。)共享指针的巨大优势在于你可以有许多类持有对它的引用,如果一个类死亡,其他类仍然有一个有效的指针。如果您有父/子引用,请确保使用std::weak_ptr 作为子级中的父级指针。

【讨论】:

  • 在没有设计内存所有权的非循环图的情况下盲目使用“shared_ptr无处不在”实际上可以确保内存泄漏。我看到你建议weak_ptr 让孩子们回到他们的父母那里打破循环依赖,这很好。但不足。循环内存所有权可能比父/子关系微妙得多。而“shared_ptr无处不在”的建议只会加剧这个问题。与不可诊断的内存泄漏相比,可诊断的运行时崩溃是一件幸事。仔细理解和设计是无可替代的。
  • shared_ptr 可能是解决方案的一部分。但不能盲目应用。
  • 我认为,在他的情况下,这将解决他的问题,他最终可能会出现一些内存泄漏,但坦率地说,我引入共享指针的所有项目,我现在都没有任何泄漏。在这一点上,他看起来不像在处理异常,而共享指针会自动为你做这件事。
  • 我问的问题实际上是“是什么原因造成的?”,Alexis Wilke 用“指针被释放了两次”为我完美地回答了这个问题。如果我阅读每个 Visual Studio 代码的含义,看起来会很有帮助,将来应该会帮助解决这样的问题。谢谢亚历克西斯,这给了我一个开始调试的地方。不幸的是,我已经用 shared_ptrs 替换了相关的 unique_ptrs,只是出现了完全相同的错误,所以该对象必须以其他方式删除。再次感谢您的指导。我真的应该开始使用智能指针了;)
猜你喜欢
  • 2019-10-04
  • 2021-05-21
  • 2012-10-11
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多