简体   繁体   English

调试断言失败:std :: vector下标超出范围

[英]Debug assertion failed: Subscript out of range with std::vector

I'm trying to fix this problem which seems like I am accessing at an out of range index, but VS fails to stop where the error occurred leaving me confused about what's causing this. 我正在尝试解决此问题,似乎我正在访问超出范围的索引,但是VS无法停止发生错误的地方,这使我感到困惑。

The Error: 错误:

Debug Assertion Failed! 调试断言失败! Program: .... File: c:\\program files\\microsoft visual studio 10.0\\vc\\include\\vector Line: 1440 Expression: String subscript out of range 程序:....文件:c:\\ program files \\ microsoft visual studio 10.0 \\ vc \\ include \\ vector行:1440表达式:字符串下标超出范围

What the program does: 该程序的作用:

There are two threads: 有两个线程:

Thread 1: 线程1:

The first thread looks (amongst other things) for changes in the current window using GetForegroundWindow() , the check happens not on a loop but when a WH_MOUSE_LL event is triggered. 第一个线程(使用其他方法)使用GetForegroundWindow()查找当前窗口中的更改,该检查不是在循环上发生,而是在触发WH_MOUSE_LL事件时发生。 The data is split into structs of fixed size so that it can be sent to a server over tcp. 数据被分成固定大小的结构,以便可以通过tcp将其发送到服务器。 The first thread and records the data (Window Title) into an std::list in the current struct. 第一个线程并将数据(窗口标题)记录到当前结构的std::list中。

if(change_in_window)
{
    GetWindowTextW(hActWin,wTitle,256);
    std::wstring title(wTitle);
    current_struct->titles.push_back(title);
}

Thread 2: 线程2:

The second thread is called looks for structs not send yet, and it puts their content into char buffers so that they can be sent over tcp. 第二个线程称为寻找尚未发送的结构,并将其内容放入char缓冲区中,以便可以通过tcp发送它们。 While I do not know exactly where the error is, looking from the type of error it was to do either with a string or a list, and this is the only code from my whole application using lists/strings (rest are conventional arrays). 虽然我不知道确切的错误位置,但从错误的类型看它是使用字符串还是使用列表,这是整个应用程序中唯一使用列表/字符串的代码(其余是常规数组)。 Also commenting the if block as mentioned in the code comments stops the error from happening. 还要注释代码注释中提到的if块,以防止发生错误。

  BOOL SendStruct(DATABLOCK data_block,bool sycn)
    {
    [..]

                int _size = 0;
// Important note, when this if block is commented the error ceases to exist, so it has something to do with the following block
                if(!data_block.titles.empty()) //check if std::list is empty
                {

                    for (std::list<std::wstring>::iterator itr  = data_block.titles.begin(); itr != data_block.titles.end() ; itr++) {
                        _size += (((*itr).size()+1) * 2); 
                    } //calculate size required. Note the +1 is for an extra character between every title
                    wchar_t* wnd_wbuffer = new wchar_t[_size/2](); //allocate space
                    int _last = 0;
    //loop through every string and every char of a string and write them down
                    for (std::list<std::wstring>::iterator itr = data_block.titles.begin(); itr != data_block.titles.end(); itr++)
                    {
                        for(unsigned int i = 0; i <= (itr->size()-1); i++)
                        {

                            wnd_wbuffer[i+_last] = (*itr)[i] ;
                        }
                        wnd_wbuffer[_last+itr->size()] = 0x00A6; // separator
                        _last += itr->size()+1;
                    }

                    unsigned char* wnd_buffer = new unsigned char[_size];
                    wnd_buffer = (unsigned char*)wnd_wbuffer;
                    h_io->header_w_size = _size;
                    h_io->header_io_wnd = 1;
                    Connect(mode,*header,conn,buffer_in_bytes,wnd_buffer,_size);
                    delete wnd_wbuffer;
                }
                else
            [..]
                return true;
            }

My attempt at thread synchronization: There is a pointer to the first data_block created (db_main) pointer to the current data_block (db_cur) 我的线程同步尝试:有一个指向创建的第一个data_block的指针(db_main),有一个指向当前data_block的指针(db_cur)

//datablock format
    typedef struct _DATABLOCK
        {
            [..]
            int logs[512];
            std::list<std::wstring> titles;
            bool bPrsd; // has this datablock been sent true/false
            bool bFull; // is logs[512] full true/false
            [..]
            struct _DATABLOCK *next;
        } DATABLOCK;    


//This is what thread 1 does when it needs to register a mouse press and it is called like this:
    if(change_in_window)
    {
        GetWindowTextW(hActWin,wTitle,256);
        std::wstring title(wTitle);
        current_struct->titles.push_back(title);
    }
    RegisterMousePress(args);
    [..]
//pseudo-code to simplify things , although original function does the exact same thing. 
    RegisterMousePress()
        {
            if(it_is_full)
            {
                db_cur->bFull= true;
                if(does db_main exist)
                {
                    db_main = new DATABLOCK;
                    db_main = db_cur;
                    db_main->next = NULL;
                }
                else
                {
                    db_cur->next = new DATABLOCK;
                    db_cur = db_cur->next;
                    db_cur->next = NULL;

                }
                SetEvent(eProcessed); //tell thread 2 there is at least one datablock ready
            }
            else
            {
            write_to_it();
            }
        }
//this is actual code and entry point of thread 2 and my attempy at synchronization
    DWORD WINAPI InitQueueThread(void* Param)
    {
        DWORD rc;
        DATABLOCK* k;
        SockWClient writer;
        k = db_main;
        while(true)
        {
            rc=WaitForSingleObject(eProcessed,INFINITE);
            if (rc== WAIT_OBJECT_0)
            {   
                do
                {
                    if(k->bPrsd)
                    {
                        continue;
                    }
                    else
                    {   
                        if(!k)
                        {break;}
                        k->bPrsd = TRUE;
    #ifdef DEBUG_NET
                        SendStruct(...);
    #endif

                    }
                    if(k->next == NULL || k->next->bPrsd ==TRUE || !(k->next->bFull))
                    {
                        ResetEvent(eProcessed);
                        break;
                    }

                } while (k = k->next); // next element after each loop
            }
        }
        return 1;

    }

Details: 细节:

Now something makes me believe that the error is not in there, because the substring error is very rare. 现在让我相信错误不在其中,因为子字符串错误非常罕见。 I have been only able to reproduce it with 100% chance when pressing Mouse_Down+Wnd+Tab to scroll through windows and keeping it pressed for some time (while it certainly happened on other cases as well). 当按下Mouse_Down + Wnd + Tab滚动窗口并保持按下一段时间(在其他情况下当然也会发生)时,我只能以100%的机会重现它。 I avoid posting the whole code because it's a bit large and confusion is unavoidable. 我避免发布整个代码,因为它太大了,并且不可避免。 If the error is not here I will edit the post and add more code. 如果错误不在这里,我将编辑帖子并添加更多代码。

Thanks in advance 提前致谢

There does not appear to be any thread synchronization here. 这里似乎没有任何线程同步。 If one thread reads from the structure while the other writes, it might be read during initialization, with a non-empty list containing an empty string (or something invalid, in between). 如果一个线程从结构中读取而另一个线程从结构中读取,则可能会在初始化期间读取该线程,并且该非空列表包含一个空字符串(或介于两者之间的无效字符串)。

If there isn't a mutex or semaphore outside the posted function, that is likely the problem. 如果发布的功能之外没有互斥或信号灯,则可能是问题所在。

All the size calculations appear to be valid for Windows, although I didn't attempt to run it… and <= … -1 instead of < in i <= (itr->size()-1) and 2 instead of sizeof (wchar_t) in new wchar_t[_size/2](); 所有尺寸的计算显示为Windows是有效的,虽然我没有尝试运行它... <= … -1 ,而不是<i <= (itr->size()-1)2代替sizeof (wchar_t)中的new wchar_t[_size/2](); are a bit odd. 有点奇怪。

The problem with your code is that while thread 2 correctly waits for the data and thread 1 correctly notifies about them, thread 2 doesn't prevent thread 1 from doing anything with them under its hands while it still process the data. 您的代码的问题在于,虽然线程2正确等待数据并且线程1正确通知了数据,但是线程2仍在处理数据时并不会阻止线程1对其进行任何操作。 The typical device used to solve such problem is the monitor pattern. 用于解决此问题的典型设备是监视器模式。

It consist of one mutex (used to protect the data, held anytime you access them) and a condition variable (=Event in Windows terms), which will convey the information about new data to the consumer. 它由一个互斥锁(用于保护数据,可在您访问它们时随时保存)和一个条件变量(以Windows术语= Event)组成,该变量将有关新数据的信息传达给使用者。

The producer would normally obtain the mutex, produce the data, release the mutex, then fire the event. 生产者通常会获取互斥体,生成数据,释放互斥体,然后触发事件。

The consumer is more tricky - it has to obtain the mutex, check if new data hasn't become available, then wait for the Event using the SignalObjectAndWait function that temporarily releases the mutex, then process newly acquired data, then release the mutex. 使用者比较棘手-它必须获取互斥量,检查是否有新数据不可用,然后使用SignalObjectAndWait函数等待事件,该函数临时释放互斥量,然后处理新获取的数据,然后释放互斥量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM