【问题标题】:Defining a smart pointer as a member variable of a class将智能指针定义为类的成员变量
【发布时间】:2021-10-19 08:03:25
【问题描述】:

标题:

CChristianLifeMinistryHtmlView m_pHtmlView  = nullptr;

来源:

m_pHtmlView = new CChristianLifeMinistryHtmlView();

尝试将其更改为使用智能指针。我可以这样做(在OnInitDialog 内):

auto m_pHtmlView2 = std::make_unique<CChristianLifeMinistryHtmlView>;

但我不知道如何将智能指针定义为CDialog 类的成员变量。我做不到:std::unique_ptr m_pHtmlView2


我看到了这个讨论 (Using smart pointers as a class member) 并基于此我在标题中尝试了这个:

//CChristianLifeMinistryHtmlView *m_pHtmlView;
std::unique_ptr<CChristianLifeMinistryHtmlView> m_pHtmlView;

但这不会编译:

6>C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.30.30704\include\memory(3087,1): error C2248: 'CChristianLifeMinistryHtmlView::~CChristianLifeMinistryHtmlView': cannot access protected member declared in class 'CChristianLifeMinistryHtmlView'
6>D:\My Programs\2022\MeetSchedAssist\Meeting Schedule Assistant\ChristianLifeMinistryHtmlView.h(104): message : compiler has generated 'CChristianLifeMinistryHtmlView::~CChristianLifeMinistryHtmlView' here
6>D:\My Programs\2022\MeetSchedAssist\Meeting Schedule Assistant\ChristianLifeMinistryHtmlView.h(22): message : see declaration of 'CChristianLifeMinistryHtmlView'
6>C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.30.30704\include\memory(3085): message : while compiling class template member function 'void std::default_delete<CChristianLifeMinistryHtmlView>::operator ()(_Ty *) noexcept const'
6>        with
6>        [
6>            _Ty=CChristianLifeMinistryHtmlView
6>        ]
6>C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.30.30704\include\memory(3195): message : see reference to function template instantiation 'void std::default_delete<CChristianLifeMinistryHtmlView>::operator ()(_Ty *) noexcept const' being compiled
6>        with
6>        [
6>            _Ty=CChristianLifeMinistryHtmlView
6>        ]
6>C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.30.30704\include\memory(3122): message : see reference to class template instantiation 'std::default_delete<CChristianLifeMinistryHtmlView>' being compiled
6>D:\My Programs\2022\MeetSchedAssist\Meeting Schedule Assistant\AvailableBrothersReportPreview.h(52): message : see reference to class template instantiation 'std::unique_ptr<CChristianLifeMinistryHtmlView,std::default_delete<CChristianLifeMinistryHtmlView>>' being compiled

更新

根据我现在拥有的 cmets 中的建议:

  • 标题:

std::unique_ptr&lt;CChristianLifeMinistryHtmlView&gt; m_pHtmlView;

  • 来源(OnInitDialog):

m_pHtmlView = std::make_unique<CChristianLifeMinistryHtmlView>();
if (m_pHtmlView != nullptr)
{
    m_pHtmlView->Create(nullptr, nullptr, AFX_WS_DEFAULT_VIEW,
                            m_rctPreviewHtml, this, 0);
    m_pHtmlView->ShowWindow(SW_SHOWNORMAL);
    if(CMeetingScheduleAssistantApp::WaitForFileToBeReady(m_strTempHtmlFile))
        m_pHtmlView->Navigate2(m_strTempHtmlFile, 0, nullptr);
}

它符合并有效。我的弹出对话框显示并且CHtmlView 派生控件可见。凉爽的。但是当我单击确定关闭对话框时,我得到一个异常:

我们如何解决这个问题?

【问题讨论】:

  • unique_ptr 需要访问CChristianLifeMinistryHtmlView 的析构函数。该错误消息似乎表明(编译器生成的)析构函数受到保护。要么公开析构函数,要么将unique_ptr&lt;CChristianLifeMinistryHtmlView&gt; 设置为friend。后者相当棘手,只能作为最后的手段。
  • @IInspectable 我将析构函数更改为公共。然后编译但m_pHtmlView 说它是空的。然后我在 OID 中尝试:m_pHtmlView = std::unique_ptr&lt;CChristianLifeMinistryHtmlView&gt;();,它仍然是空的。因此,虽然它全部编译,但我没有看到。
  • 在类定义中:std::unique_ptr&lt;CChristianLifeMinistryHtmlView&gt; m_pHtmlView;。在构造函数中:m_pHtmlView = std::make_unique&lt;CChristianLifeMinistryHtmlView&gt;();(注意末尾的一对括号;std::make_unique&lt;CChristianLifeMinistryHtmlView&gt; 是需要实际调用的函数)。
  • 这看起来像一个双重删除错误。您是否尝试在某个时候手动删除 unique_ptr 中保存的指针,例如来自析构函数?
  • 在代码中没有显示的地方,你有双重破坏。可能不是直接属于m_pHtmlView,而是属于它所属的类。

标签: visual-c++ mfc smart-pointers


【解决方案1】:

CHtmlView派生自CFormView -> CView,在CView::PostNcDestroydelete this;中删除自己,所以内存已经被管理了。

new替换为std::make_unique,并立即调用release(),因为您不希望unique_ptr再删除它。

//m_pHtmlView = new CChristianLifeMinistryHtmlView();
m_pHtmlView = std::make_unique<CChristianLifeMinistryHtmlView>().release();

如果您在原始代码中编写了newdelete(这也意味着您至少覆盖了CMyHtmlView::PostNcDestroy),那么unique_ptr 可以用来替换newdelete

在这种情况下,原始代码中只有 new。你不希望unique_ptr 管理delete

【讨论】:

  • 谢谢。我已按照说明更改了 OID 中变量的声明。但是我的班级没有PostNcDestroy,所以我猜这是默认的CHtmlView 版本。我被称为delete 的地方在我的对话OnDestroy 中。实际上,我原来的OnDestroy 似乎只是调用DestroyWindow() 然后将指针设置为null。没有实际的delete 电话。
  • 所以看起来我只是按照您的指示创建它,不要删除它,因为它会被CView::PostNcDestroy 删除我猜。我没有内存泄漏。而且根据源代码管理,我从来没有打电话给delete m_pHtmlView
  • 好的好的。您应该创建一个单独的项目并编写一个小的“hello world”控制台程序,以测试unique_ptr 和其他C++ 功能。在具有CHtmlView 和其他已经很复杂的类的大型 MFC 项目中学习这一点很困难。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-12
  • 1970-01-01
  • 2011-12-25
  • 2020-06-19
  • 2013-03-16
  • 2014-01-24
  • 1970-01-01
相关资源
最近更新 更多