gpt4 book ai didi

c++ - 继承自 CString 导致内存不足异常

转载 作者:太空狗 更新时间:2023-10-29 21:43:51 24 4
gpt4 key购买 nike

我有以下继承自 MFC CString 的字符串类

class TString : public CString
{
public:
TString() : CString(_T(""))
{
}

TString(LPCTSTR str) : CString(str)
{
}
};

我在一个经常使用 + 运算符和 TString 的方法中出现内存不足异常,所以我尝试进行如下测试

TString str;
TCHAR buffer[] = "Hello world, Hello world, Hello world, Hello world, Hello world, Hello world";

uint i = 0;
while(i++ < 100000000)
{
str = buffer;
str += buffer;
}

占用大量内存并以内存不足异常结束,这是执行最后一个代码后任务管理器内存更改的快照

enter image description here

当我用 CString 替换 TString 时,这很正常,没有内存不足异常,任务管理器中的内存也很稳定,就像这个镜头一样

enter image description here

我尝试了以下2种状态

  1. 我创建了另一个 exe 应用程序,它依赖于包含 TString 类的同一个库,它像 CString 一样工作得很好
  2. 我在 while 循环中调用了 Sleep(1),它使内存快速变化并且也很稳定我该怎么做才能解决这样的问题??

编辑:

当我重新编译解决方案时我的解释有一些错误 CString 甚至 std::string 也有相同的行为 我认为新的运算符重载 我创建了一个自定义类调用 malloc 并在析构函数中释放它也导致为了同样的行为,我将该测试代码移动到我的应用程序的第一个入口点到我的应用程序的构造函数,它继承自 CWinAppEx 代码工作正常然后我查看了 InitInstance 我发现内存泄漏检测 4 行代码如下

int tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
tmpDbgFlag |= _CRTDBG_DELAY_FREE_MEM_DF;//<====this is the evil after comment everything is fine
tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(tmpDbgFlag);

我一直都知道这是人为错误。造成灾难。

我刚刚评论了这行

tmpDbgFlag |= _CRTDBG_DELAY_FREE_MEM_DF;

这就解决了。这个答案也讲了这个标志的用法Finding heap corruption我感谢所有试图帮助解决这个问题的人,我希望它能有所帮助。

最佳答案

从一个没有虚拟析构函数的类继承是一个非常糟糕的主意。以下引自 Scott Meyers 的“Effective C++:改进程序和设计的 55 种具体方法,第三版”。

The problem is that getTimeKeeper returns a pointer to a derived class object (e.g., AtomicClock), that object is being deleted via a base class pointer (i.e., a TimeKeeper* pointer), and the base class (TimeKeeper) has a non-virtual destructor. This is a recipe for disaster, because C++ specifies that when a derived class object is deleted through a pointer to a base class with a non-virtual destructor, results are undefined. What typically happens at runtime is that the derived part of the object is never destroyed. If a call to getTimeKeeper happened to return a pointer to an AtomicClock object, the AtomicClock part of the object (i.e., the data members declared in the AtomicClock class) would probably not be destroyed, nor would the AtomicClock destructor run. However, the base class part (i.e., the TimeKeeper part) typically would be destroyed, thus leading to a curious “partially destroyed” object. This is an excellent way to leak resources, corrupt data structures, and spend a lot of time with a debugger.

总而言之,当您从没有虚析构函数的类派生时,您会使用指向该对象的指针,当您删除该指针时,该对象只会部分销毁。这显然只发生在指针指向基类而不是指针指向类本身时。

如果您必须扩展一个没有虚拟析构函数的类,最好通过包含来实现。那就是创建一个新类,它不是从您希望扩展的类派生的。然后拥有一个您希望扩展的类型的成员变量,并实现您希望扩展的类中的所有函数,作为您希望扩展的类中适当函数的包装器。

例如。

class TString /* do not derive from CString */
{
private:
CString m_string;
TString() :
m_string()
{
}

TString(const TCHAR *str) :
m_string(str)
{
}

int GetLength() const
{
return m_string.GetLength();
}

/* All the other functions in the CString class here. */

/* Your additions to the CString class here. */
}

当然,在最新版本的 MFC 中,CString 实际上是一个模板类,因此您也许应该将您的类设为模板类,如下所示。

template< typename BaseType >
class TStringT
{
/* The same as above but use BaseType instead of TCHAR. */
}

然后执行以下操作。

typedef TStringT< wchar_t > TStringW;
typedef TStringT< char > TStringA;
typedef TStringT< TCHAR > TString;

希望对您有所帮助。

关于c++ - 继承自 CString 导致内存不足异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21738026/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com