如何释放在孩子diaolog创建的CWin对象,以避免内存泄漏 [英] How to free CWin objects created in a child diaolog to avoid memory leaks

查看:196
本文介绍了如何释放在孩子diaolog创建的CWin对象,以避免内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在子对话框中创建一个CStatic控件,它工作正常。问题是,在关闭子对话框后,内存不能正确释放。

I'm creating a a CStatic conrol in a child dialog, which works fine. The problem is that after closing the child dialog the memory is not freed correctly.

我试图覆盖 PostNCDestoy 描述在这个线程:
这是一个内存泄漏在MFC
但是这给我一个未处理的异常通过调用删除这个。

I tried to overwrite PostNCDestoy like described in the this thread: Is this a memory leak in MFC But this gives me an unhandled exception by calling "delete this".

任何想法是什么正确的方法是释放CStatic,CButtons避免内存泄漏?

Any idea what the right way is to release CStatic, CButtons to avoid memory leaks?

CChildDlg.h

class CChildDlg
{
  std::vector<CStatic*> m_images;
  void addNewImage(const int &xPos, const int &yPos)
  ...
}

CChildDlg.cpp

void CChildDlg::addNewImage(const int &xPos, const int &yPos){

  CImage imgFromFile;
  CStatic *img = new CStatic;

  imgFromFile.Load(_T("someImg.jpg"));
  int width = imgFromFile.GetWidth();
  int height = imgFromFile.GetHeight();


  img->Create(_T("Image"), WS_CHILD | WS_VISIBLE | SS_BITMAP,
    CRect(xPos, yPos, xPos + width, yPos + height), this, 10910);

  HBITMAP hbmOld = img->SetBitmap(imgFromFile.Detach());
  if (hbmOld != nullptr){
    ::DeleteObject(hbmOld);
  }
  m_images.pushback(img);
}



根据这个线程中的建议,我改变了如下代码:

Based on the recommendations in this thread I changed the code like followed:

CChildDlg.h

class CChildDlg
{
private:
  typedef std::vector<std::unique_ptr <CStatic>> CStaticImgs;
  CStaticImgs m_images;
  void addNewImage(const int &xPos, const int &yPos)
  ...
}

CChildDlg.cpp

void CChildDlg::addNewImage(const int &xPos, const int &yPos){

  CImage imgFromFile;
  std::unique_ptr<CStatic> img(new CStatic);

  imgFromFile.Load(_T("someImg.jpg"));
  int width = imgFromFile.GetWidth();
  int height = imgFromFile.GetHeight();

  img->Create(_T("Image"), WS_CHILD | WS_VISIBLE | SS_BITMAP,
     CRect(xPos, yPos, xPos + width, yPos + height), this, 10910);

  HBITMAP hbmOld = img->SetBitmap(imgFromFile.Detach());
  if (hbmOld != nullptr){
     ::DeleteObject(hbmOld);
  }
  m_images.pushback(std::move(img));
}

代码运行正常,但泄漏仍然存在。只有当我删除我设置位图到CStatic的行,泄漏消失:

The code works fine, but the leak is still there. Only if I'm removing the line where I'm setting the Bitmap to the CStatic the leak disappears:

//HBITMAP hbmOld = img->SetBitmap(imgFromFile.Detach());
//if (hbmOld != nullptr){
  //::DeleteObject(hbmOld);
//}

因此,它必须与接管CImage到CStatic不知何故。我最多加载100个图像到对话框。每次打开对话框我仍然可以看到一个显着提高的内存,关闭后不会下降。

So, it has to be related to taking over the ownership of the CImage to the CStatic somehow. I'm loading up to 100 images to the dialog. By every opening of the dialog I still can see a significant raise of the memory, which not drops after closing it.

任何其他建议可能错误的错误?

Any other suggestion what might be wrong of missing?

推荐答案

这个简单的解决方案是简单地遍历你的容器类,调用 delete 每个指针。例如:

The naïve solution would be to simply iterate through your container class, calling delete on each pointer. Something like:

for (auto i : m_images)                       { delete i; }            // on C++11





for (size_t i = 0; i < m_images.size(); ++i)  { delete m_images[i]; }  // on C++03



如果你在你的析构函数中做的或响应 WM_DESTROY 消息( OnDestroy 在MFC中),它将确保您的每个 CStatic 实例被销毁,解决内存泄漏问题。

If you do this in your destructor or in response to the WM_DESTROY message (OnDestroy in MFC), it will ensure that each of your CStatic instances are destroyed, solving the memory leak problem.

但这不是最好的解决方案。在C ++中,您应该利用范围绑定资源管理(SBRM),也更通常称为RAII。这涉及到使用语言功能来自动清除对象,而不必手动进行。这不仅使代码更清晰,而且确保你永远不会忘记,你的代码是完全异常安全的,甚至可以更高效。

But this is not the best solution. In C++, you should be taking advantage of Scope-Bound Resource Management (SBRM), also more commonly known as RAII. This involves the use of language features to automatically clean up objects, rather than having to do it manually. Not only does this make the code cleaner, but it ensures that you never forget, that your code is fully exception-safe, and may even be more efficient.

你只需将对象本身存储在容器类中。也就是说,不是 std :: vector< CStatic *> ,你只需要 std :: vector< CStatic> 。这样,当矢量容器被销毁时(由于SBRM,它被超出范围时自动发生),它包含的所有对象也被毁坏( ie ,它们的析构函数被称为自动)。

Typically, you would just store the objects themselves in the container class. That is, instead of std::vector<CStatic*>, you would just have std::vector<CStatic>. That way, whenever the vector container is destroyed (which happens automatically when it goes out of scope, thanks to SBRM), all of the objects that it contains get destroyed as well (i.e., their destructors are called automatically).

但是,标准库容器要求对象是可复制的或可移动的。从 CObject 派生的MFC类不是可复制的,并且可能不是可移动的(给定MFC的年龄和使对象不可复制隐含地使其不可复制的标准习语)活动)。这意味着这不会工作:你不能存储 CStatic 对象本身在向量或其他容器类中。

However, the standard-library containers require that objects be either copyable or movable. The MFC classes derived from CObject are not copyable, and presumably not movable either (given the age of MFC and the standard idioms for making an object non-copyable implicitly making it non-movable). That means this won't work: you can't store CStatic objects themselves in a vector or other container class.

幸运的是,现代C ++有这个问题的解决方案:。智能指针就是他们听起来像的:一个包装裸(哑)指针的类,给它超级大国。智能指针提供的智能之一是SBRM。每当智能指针对象被销毁时,它会自动删除其底层的哑指针。这使得你,这个谦逊的程序员,从来不必写一个 delete 语句。事实上,你在C ++中几乎不需要做的两件事情是:

Fortunately, modern C++ has a solution for this problem: the smart pointer. Smart pointers are just what they sound like: a class that wraps the bare ("dumb") pointer, giving it superpowers. Chief among the smarts offered by a smart pointer is SBRM. Whenever the smart pointer object gets destroyed, it automatically deletes its underlying dumb pointer. This frees you, the humble programmer, from ever having to write a single delete statement. In fact, two things you should almost never have to do in C++ are:


  • 显式写 delete

  • 使用原始指针

CObject - 派生类,是在你的向量中存储智能指针。语法不太漂亮,但是使用typedef很容易解决:

So my recommendation, given the limitations of MFC's CObject-derived classes, is to store smart pointers in your vector. The syntax isn't pretty, but that's trivially solved with a typedef:

typedef std::vector<std::unique_ptr<CStatic>> CStaticVector;   // for C++11

(对于C ++ 03,因为 std :: auto_ptr 不能在标准容器中使用 [再次,因为它不可复制],您将需要使用不同的智能指针,如 Boost智能指针库。)

(For C++03, since std::auto_ptr cannot be used in a standard container [again, because it is not copyable], you would need to use a different smart pointer, such as the Boost Smart Pointers library.)

无需手动内存管理,没有更多的内存泄漏,不再头痛。在C ++中工作是从屁股痛苦到快速,有趣,高效的。

No more manual memory-management, no more memory leaks, no more headaches. Working in C++ literally goes from being a pain in the butt to being fast, fun, and efficient.

这篇关于如何释放在孩子diaolog创建的CWin对象,以避免内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆