C++ 调整动态字符串的大小会导致内存泄漏

C++ 调整动态字符串的大小会导致内存泄漏,c++,memory-leaks,dynamic-allocation,C++,Memory Leaks,Dynamic Allocation,我从一个非常简单的程序开始: #include <TBString.h> int main(int argv, char** argc) { tb::String test(""); test = "Hello World!"; return 0; } 因此,看起来是一个空tb::字符串(大小为0)导致了内存泄漏。通过该程序确认,该程序不会泄漏: #include <TBString.h> int main(int argv, char**

我从一个非常简单的程序开始:

#include <TBString.h>

int main(int argv, char** argc)
{
    tb::String test("");
    test = "Hello World!";

    return 0;
}
因此,看起来是一个空tb::字符串(大小为0)导致了内存泄漏。通过该程序确认,该程序不会泄漏:

#include <TBString.h>

int main(int argv, char** argc)
{
    tb::String test("Hello World!");

    return 0;
}
这就是我怀疑的问题所在。现在,我的问题变成:

<如何在C++中重新分配内存,而不在CRT调试器中触发内存泄漏?

建造商:

TB_INLINE StringBase<char>::StringBase(const char* a_String)
{
    m_Length = StringHelper::GetLength<char>(a_String);
    m_Maximum = m_Length + 1;
    m_Data = new char[m_Maximum];
    StringHelper::Clear<char>(m_Data, m_Maximum);

    StringHelper::Copy<char, char>(m_Data, a_String, m_Length);

    _AppendSingle = &StringBase<char>::_AppendDynSingle;
    _AppendDouble = &StringBase<char>::_AppendDynDouble;
}
TB_内联StringBase::StringBase(const char*a_字符串)
{
m_Length=StringHelper::GetLength(一个_字符串);
m_最大值=m_长度+1;
m_数据=新字符[m_最大值];
StringHelper::Clear(m_数据,m_最大值);
StringHelper::Copy(m_数据、a_字符串、m_长度);
_AppendSingle=&StringBase::\u AppendDynSingle;
_AppendDouble=&StringBase::\u AppendDynDouble;
}
析构函数:

TB_INLINE StringBase<char>::~StringBase()
{
    if (m_Data) { delete [] m_Data; }
}
TB_内联StringBase::~StringBase()
{
如果(m_数据){delete[]m_数据;}
}
分配操作员:

TB_INLINE StringBase<char>& StringBase<char>::operator = (const char *a_String)
{
    Clear();
    return (this->*_AppendSingle)(a_String);
}
TB_内联StringBase&StringBase::operator=(const char*a_字符串)
{
清除();
return(this->*_AppendSingle)(一个_字符串);
}
附加函数:

template <typename C>
TB_INLINE StringBase<C>& StringBase<C>::Resize(int a_Maximum /*= -1*/)
{
    if (!m_Data)
    {
        m_Maximum = (a_Maximum == -1) ? 4 : a_Maximum;
        m_Data = new C[m_Maximum];
        StringHelper::Clear<C>(m_Data, m_Maximum);
    }
    else
    {
        int newmax = (a_Maximum == -1) ? (m_Maximum * 2) : a_Maximum;

        C* temp = new C[newmax];
        StringHelper::Clear<C>(temp, newmax);
        if (m_Length > 0) { StringHelper::Copy(temp, m_Data, m_Length); }
        delete [] m_Data;
        m_Data = temp;

        m_Maximum = newmax;
    }

    return *this;
}
template<>
TB_INLINE StringBase<char>& StringBase<char>::_AppendDynSingle(const char* a_String)
{
    if (!a_String) { return *this; }

    int src_len = StringHelper::GetLength<char>(a_String);

    // check size

    if (m_Maximum == -1)
    {
        m_Maximum = src_len + 1;
        m_Data = new char[m_Maximum];
        StringHelper::Clear<char>(m_Data, m_Maximum);
        m_Length = 0;
    }

    int checklen = m_Length + src_len + 1;
    if (checklen > m_Maximum)
    {
        while (checklen > m_Maximum) { m_Maximum *= 2; }
        Resize(m_Maximum);
    }

    // append

    strcat(m_Data, a_String);

    // new length

    m_Length += src_len;

    return *this;
}
void ScopeTest()
{
    tb::String test("Hello World!");
    test = "Hello World! Again!";
}
模板
TB_内联StringBase和StringBase::_AppendDynSingle(const char*a_字符串)
{
如果(!a_String){return*this;}
int src_len=StringHelper::GetLength(一个字符串);
//检查尺寸
如果(m_最大值==-1)
{
m_max=src_len+1;
m_数据=新字符[m_最大值];
StringHelper::Clear(m_数据,m_最大值);
m_长度=0;
}
int checklen=m_Length+src_len+1;
如果(勾选Len>m_最大值)
{
而(checklen>m_-max){m_-max*=2;}
调整大小(最大m_);
}
//附加
strcat(m_数据,一个_字符串);
//新长度
m_长度+=src_长度;
归还*这个;
}

请注意:我不想使用
std::string
std::vector
,我想修复此函数。

您正在泄漏在执行赋值后构造函数中初始化的任何字节。要调试泄漏,请在执行分配时逐步使用调试器。在
m_Data
变量上设置一个观察点可能很有用,这样调试器在更改值时就会停止。

这将是一个很长的观察点

首先,我决定检查一下自己是否神智正常。CRT内存调试器是否正常工作

int* src_test = new int[10];
for (int i = 0; i < 10; i++) { src_test[i] = i; }
int* dst_test = new int[10];
for (int i = 0; i < 10; i++) { dst_test[i] = src_test[i]; }
delete [] src_test;
好的,还有什么?嗯,也许解构主义者没有被叫来。让我们把它放在一个函数中:

template <typename C>
TB_INLINE StringBase<C>& StringBase<C>::Resize(int a_Maximum /*= -1*/)
{
    if (!m_Data)
    {
        m_Maximum = (a_Maximum == -1) ? 4 : a_Maximum;
        m_Data = new C[m_Maximum];
        StringHelper::Clear<C>(m_Data, m_Maximum);
    }
    else
    {
        int newmax = (a_Maximum == -1) ? (m_Maximum * 2) : a_Maximum;

        C* temp = new C[newmax];
        StringHelper::Clear<C>(temp, newmax);
        if (m_Length > 0) { StringHelper::Copy(temp, m_Data, m_Length); }
        delete [] m_Data;
        m_Data = temp;

        m_Maximum = newmax;
    }

    return *this;
}
template<>
TB_INLINE StringBase<char>& StringBase<char>::_AppendDynSingle(const char* a_String)
{
    if (!a_String) { return *this; }

    int src_len = StringHelper::GetLength<char>(a_String);

    // check size

    if (m_Maximum == -1)
    {
        m_Maximum = src_len + 1;
        m_Data = new char[m_Maximum];
        StringHelper::Clear<char>(m_Data, m_Maximum);
        m_Length = 0;
    }

    int checklen = m_Length + src_len + 1;
    if (checklen > m_Maximum)
    {
        while (checklen > m_Maximum) { m_Maximum *= 2; }
        Resize(m_Maximum);
    }

    // append

    strcat(m_Data, a_String);

    // new length

    m_Length += src_len;

    return *this;
}
void ScopeTest()
{
    tb::String test("Hello World!");
    test = "Hello World! Again!";
}
它能工作,但会泄漏。让我们绝对确保解构器被调用

void ScopeTest()
{
    tb::String* test = new tb::String("Hello World!");
    *test = "Hello World! Again!";
    delete test;
}
还在漏水。那么,
=
操作符是做什么的呢?它清除并追加。让我们手动执行此操作:

void ScopeTest()
{
    tb::String* test = new tb::String("Hello World!");
    test->Clear();
    test->Append("Hello World! Again!");
    delete test;
}
同样的结果,所以它与运算符无关。我想知道如果我删除了
清除

void ScopeTest()
{
    tb::String* test = new tb::String("Hello World!");
    test->Append("Hello World! Again!");
    delete test;
}
好吧,它。。。等等,什么?它不漏吗?然后,
Clear
做什么

template <>
TB_INLINE StringBase<char>& StringBase<char>::Clear()
{
    if (m_Data)
    {
        StringHelper::Clear<char>(m_Data, m_Maximum);
    }

    m_Length = 0;

    return *this;
}
再次泄漏字节

但是等一下,它仍然在清除
tb::String
?长度设置为0,数据归零,即使主体已注释掉。怎么,怎么

好的,编译器,让我们看看你编译这个:

我要杀了在这件事上花了三个小时的人

Project Game -> Toolbox.lib
哦,等等。那是我


TL;DR:我链接到了string类的一个旧版本,导致了各种奇怪的行为,包括内存泄漏。

这个问题似乎主要是关于
tb::string
类的。这是您自己的还是来自某个库?什么是
tb::String
?严重的事情,还是被你砍掉了?@user1240436-1。在数组上使用
delete ptr
会导致堆损坏。@KonradRudolph-有很多借口可以解释:您正在编写自己的智能指针类;您使用的是C++98之前的编译器;您正在编写嵌入式(独立)应用程序;或者你只是想找点乐子@罗德里戈再次读了我的评论,我说“在你的代码中”。我特别提到OP的用例。我有些人同意嵌入式环境,但这不利于使用
delete
,也不利于智能指针。指针乐趣并不是一个严肃的应用。但即使在一般情况下,我也看不出这几个边缘案例如何被称为“许多借口”。
/*template <>
TB_INLINE StringBase<char>& StringBase<char>::Clear()
{
    if (m_Data)
    {
        StringHelper::Clear<char>(m_Data, m_Maximum);
    }

    m_Length = 0;

    return *this;
}*/
Project Toolbox -> $(OutDir)\$(ProjectName)_d.lib
Project Game -> Toolbox.lib