动态分配的LPTSTR(TCHAR *)和delete []运算符的行为不稳定?

时间:2011-07-12 04:36:51

标签: c++ windows pointers dynamic

我正在尝试构建一个处理String运算符的类。但是,由于没有令人信服的理由,它有时会在delete []运算符期间崩溃。我使用strsafe库来执行所有内部字符串操作。

// QString的

LPTSTR m_string;

void QString::operator +=(const QString &_in) //Concat m_string with _in.m_string
{
    size_t size = strlength(m_string) + strlength(_in.m_string) +1; //new size
    LPTSTR buffer = new TCHAR[size]; //alloc buffer
    ::StringCchCopy(buffer,strlength(m_string)+1,m_string); //copy current m_string to buffer

    ::StringCchCat(buffer, size, _in.m_string); //concat buffer with the input

    Replace(buffer); //replace this object with m_string

    delete[] buffer; //dealloc
}


void QString::Replace(LPCTSTR src) //replace m_string with src
{
    size_t size = strlength(src)+1; //new size
    Alloc(size);
    ::StringCchCopy(m_string,size,src); //copy src to m_string
}


void QString::Alloc(size_t size) //Dynamic allocation
{
    if(m_string != NULL) Free();
    m_string = new TCHAR[size+1];
}


void QString::Free()  //Free m_string
{
        delete[] m_string; //Sometime crashes here
        m_string = NULL;
}


QString ToStr(int _in) //Convert Integer to qstring
{
    int size = 1;
    int f = _in;

    while(f > 0)
    {
        f /=10;
        size++;
    }

    TCHAR* buf = new TCHAR[size];

    for(int i = 0; i < size; i++) buf[i] = (TCHAR)TEXT("");

    QString result(L"undef");

    if(::_itow_s(_in,buf,size,10) == 0) //No error code = ok 
    {
        result = buf;
    }
    delete[] buf;
    return result;
}

//示例1:未崩溃

int ::WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
{
    QString a(L"");
    a += L"TEST";
    a += ToStr(1000);

::MessageBox(0,a.GetStr(),L"NOTHING",MB_OK);

        return 0;
}

//示例2:打印奇怪的字符加上一些当前字符(Unicode问题?)

 int ::WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
{
    QString a(L"");
    a += L"TESTTESTESTEST";
    a += ToStr(1000);
    ::MessageBox(0,a.GetStr(),L"NOTHING",MB_OK);

    return 0;
}

//示例3:加载时崩溃

int ::WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
{
    QString a(L"");
    a += L"TESTTESTESTEST";
    a += ToStr(1000);
    a += L"TESTESTEST";
    a += ToStr(100);
    ::MessageBox(0,a.GetStr(),L"NOTHING",MB_OK);

    return 0;
}

它在Free()中的delete []运算符上崩溃了。有错误

HEAP [StringTest.exe]:为RtlFreeHeap指定的无效地址(003C0000,003C46A8)

HEAP [StringTest.exe]:003C4750处的堆块修改为003C475C,请求大小超过4

4 个答案:

答案 0 :(得分:1)

构造函数不会将m_string初始化为NULL(根据您自己的评论)。这导致随机的Free()失败。

正如selbie所说,此代码中还存在其他错误和效率低下的问题。例如,替换始终重新分配,即使从已分配的+ =调用也是如此。并且在Replace和Alloc中都添加了1,表明您不清楚哪些函数采用包含终结符的值,哪些函数不包含终结符。

除非这是一个学习或家庭作业练习,否则我强烈建议不要编写自己的字符串类 - 这将比你使用std :: string(或ATL ::)更加努力地获得一些合理有效的工作。 CString如果你愿意的话。)

马丁

答案 1 :(得分:1)

另一个答案:

我的通灵能力告诉我,如果QString没有复制构造函数,那么当ToStr()在堆栈上返回QString的“副本”时,可能会发生不好的事情。

答案 2 :(得分:0)

我看到很多错误。

对于初学者,如果将0传递给ToStr函数,则只会分配一个内存字符串来保存字符串“0”,这是两个字节('0'+ null char)。此外,如果将负整数传递给此函数,则会发生其他不良事件。你最好只分配超过你需要的东西而不试图计算“确切”的大小。

int size = sizeof(_in) * 4 + 1;

你的strcpy都没有(即使使用StringCch功能)让我感觉良好。

我建议分配2倍所需的“大小”,然后通过调试仔细研究缓冲区和m_string的内存地址,如果strcpy超出“size-1”字节(不包括null终止字符)。 / p>

答案 3 :(得分:0)

您的整个分配和自由算法是基于m_string已初始化为NULL的事实。你在构造函数中完成了吗(我在这里没有看到它)?

顺便说一下,您可能与名为Alloc()的CRT库函数发生冲突。 http://msdn.microsoft.com/en-us/library/dd492420%28VS.100%29.aspx

计算整数字符串长度的算法不正确。你从size = 1开始,你应该从size = 0开始。另外,你需要处理特殊情况,其中0 == f:0绝对是一个数字,占用1个字符。你有一个1分之一的错误(fencepost错误),其中整数的大小总是1太大。

QString ToStr(int _in) //Convert Integer to qstring
{
    int size = 0;
    int f = _in;

    if (0==f) {
        size=1;
    } else {
        while(f > 0) {
            f /=10;
            size++;
        }
    }
<\ n>在Replace()中,Alloc()增加2个字符。

size_t size = strlength(src)+1;

应该是

size_t size = strlength(src);

如果你需要一个额外的字符:: StringCchCopy(m_string,size,src);在那里放大小+ 1。或者更改您的Alloc,以便它准确分配您要求的字符数(如名称所示)。