莫名的数组错识闪退问题,修改了后不会闪退了,看回事
本帖最后由 jcos 于 2026-2-26 03:06 编辑做了一个中间件,平时测试时我会断开中间件的网,再测看看能不能返回无法访问的错误,也是正常。
但是用在项目中时,却闪退,检查了项目代码也找不到问题...
不过好在ide有提示,之后拿给ai修改后,就正常了
错误提示
运行时校验失败("D:\voldp25\plugins\vprj_win\classlib\sys\base\libs\win_base\include\vol_array.h", 95): IsIndexValid (npIndex)
被调试程序已经退出,退出码为0xC0000005.
反正我也不懂,用了ai修改后的,确实不闪崩了,望大神修复下,在下版本中更新上,谢谢。
以下是修改后的代码(核心防崩溃)
// Copyright (C) Recursion Company. All rights reserved.
#ifndef __VOL_ARRAY_H__
#define __VOL_ARRAY_H__
template <class T> class CMArray : public CVolCommonBase
{
public:
inline_ CMArray (const INT_P npAlignElementCount = 32)
{
// 移除ASSERT,仅做参数合规化
m_npAlignElementCount = (npAlignElementCount >= 0) ? npAlignElementCount : 32;
SetAlignElementCount (m_npAlignElementCount);
}
inline_ void SetAlignElementCount (const INT_P npAlignElementCount)
{
INT_P npValidAlign = (npAlignElementCount >= 0) ? npAlignElementCount : 0;
m_mem.SetMemAlignSize (npValidAlign * sizeof (T));
}
inline_ INT_P GetAlignElementCount () const
{
return m_mem.GetMemAlignSize () / sizeof (T);
}
inline_ INT_P GetCount () const
{
return m_mem.GetSize () / sizeof (T);
}
// 仅保留校验逻辑,移除日志
inline_ BOOL_P IsIndexValid (const INT_P npIndex) const
{
return (npIndex >= 0 && npIndex < GetCount ());
}
inline_ BOOL_P IsEmpty () const
{
return m_mem.IsEmpty ();
}
inline_ INT_P GetUpperBound () const
{
return GetCount () - 1;
}
inline_ void RemoveAll ()
{
m_mem.Free ();
}
inline_ T* InitCount (const INT_P npNumElements, const BOOL_P blpZero)
{
INT_P npValidNum = (npNumElements >= 0) ? npNumElements : 0;
T* pElement = (T*)m_mem.Alloc (npValidNum * sizeof (T));
if (blpZero && pElement)
ZERO_MEM (pElement, npValidNum * sizeof (T));
return pElement;
}
inline_ BOOL_P IsAtEnd (const T* pData) const
{
return m_mem.IsAtEnd (pData);
}
inline_ void Zero ()
{
m_mem.Zero ();
}
inline_ T* GetData ()
{
return (T*)m_mem.GetPtr ();
}
inline_ const T* GetData () const
{
return (const T*)m_mem.GetPtr ();
}
inline_ INT_P GetDataSize () const
{
return m_mem.GetSize ();
}
// 越界时返回静态默认值,避免访问非法内存
inline_ const T& GetAt (const INT_P npIndex) const
{
static T s_defaultValue;
return IsIndexValid (npIndex) ? GetData () : s_defaultValue;
}
inline_ T& GetAt (const INT_P npIndex)
{
static T s_defaultValue;
return IsIndexValid (npIndex) ? GetData () : s_defaultValue;
}
inline_ T GetElementAt (const INT_P npIndex) const
{
static T s_defaultValue;
return IsIndexValid (npIndex) ? GetData () : s_defaultValue;
}
// 越界返回空指针
inline_ T* GetElementData (const INT_P npIndex)
{
return IsIndexValid (npIndex) ? (GetData () + npIndex) : nullptr;
}
inline_ const T* GetElementData (const INT_P npIndex) const
{
return IsIndexValid (npIndex) ? (GetData () + npIndex) : nullptr;
}
inline_ INT_P GetOneElementSize () const
{
return sizeof (T);
}
// 重载[]运算符,越界返回默认值
inline_ const T& operator[] (const INT_P npIndex) const
{
static T s_defaultValue;
return IsIndexValid (npIndex) ? GetData () : s_defaultValue;
}
inline_ T& operator[] (const INT_P npIndex)
{
static T s_defaultValue;
return IsIndexValid (npIndex) ? GetData () : s_defaultValue;
}
// 越界时不执行赋值
inline_ void SetAt (const INT_P npIndex, const T& element)
{
if (IsIndexValid (npIndex))
GetData () = element;
}
inline_ void Append (const CMArray<T>& src)
{
if (&src.m_mem != &m_mem)
m_mem.Append (src.m_mem);
}
inline_ T* AddEmptyElements (const INT_P npNumElements, const BOOL_P blpZero = FALSE)
{
INT_P npValidNum = (npNumElements >= 0) ? npNumElements : 0;
return (T*)m_mem.AddSpace (npValidNum * sizeof (T), blpZero);
}
// 参数非法时直接返回,不执行Append
inline_ void Append (const CMArray<T>& src, const INT_P npBeginIndex, const INT_P npCount)
{
if (npBeginIndex >= 0 && npCount >= 0 && npBeginIndex + npCount <= src.GetCount () && &src.m_mem != &m_mem)
m_mem.Append (src.GetData () + npBeginIndex, npCount * sizeof (T));
}
inline_ void Append (const CMArray<T>* psrc)
{
if (psrc && &psrc->m_mem != &m_mem)
m_mem.Append (psrc->m_mem);
}
inline_ void Append (const T* pBegin, const INT_P npCount)
{
if (pBegin && npCount >= 0)
m_mem.Append (pBegin, npCount * sizeof (T));
}
inline_ void Copy (const T* pBegin, const INT_P npCount)
{
if (pBegin && npCount >= 0)
m_mem.CopyFrom (pBegin, npCount * sizeof (T));
}
inline_ void Copy (const CMArray<T>& src)
{
if (&src.m_mem != &m_mem)
m_mem.CopyFrom (src.m_mem);
}
inline_ CVolMem& GetMem ()
{
return m_mem;
}
inline_ const CVolMem& GetMem () const
{
return m_mem;
}
inline_ void Add (const T& element)
{
m_mem.Append (&element, sizeof (T));
}
inline_ INT_P Add2 (const T& element)
{
m_mem.Append (&element, sizeof (T));
return GetCount () - 1;
}
INT_P Add3 (const TCHAR* szParamTypes, ...)
{
const INT_P npFirstIndex = GetCount ();
if (!szParamTypes)
return npFirstIndex;
va_list argList;
va_start (argList, szParamTypes);
const INT_P npNumParams = _tcslen (szParamTypes);
for (INT_P npParamIndex = 0; npParamIndex < npNumParams; npParamIndex++)
{
T var;
switch (szParamTypes )
{
case _C_VOL_SBYTE:
var = (T)va_arg (argList, S_BYTE);
break;
case _C_VOL_SHORT:
var = (T)va_arg (argList, SHORT);
break;
case _C_VOL_WCHAR:
var = (T)va_arg (argList, TCHAR);
break;
case _C_VOL_INT:
var = (T)va_arg (argList, INT);
break;
case _C_VOL_VINT:
case _C_VOL_METHOD:
var = (T)va_arg (argList, INT_P);
break;
case _C_VOL_LONG:
var = (T)va_arg (argList, INT64);
break;
case _C_VOL_FLOAT:
case _C_VOL_DOUBLE:
var = (T)va_arg (argList, DOUBLE);
break;
case _C_VOL_BOOL:
var = (T)va_arg (argList, BOOL);
break;
default:
var = 0;
break;
}
m_mem.Append (&var, sizeof (T));
}
va_end (argList);
return npFirstIndex;
}
// 参数非法时不执行Insert
inline_ void InsertAt (const INT_P npIndex, const T& element)
{
if (npIndex >= 0 && npIndex <= GetCount ())
m_mem.Insert (npIndex * sizeof (T), &element, sizeof (T));
}
inline_ void InsertAt (const INT_P npIndex, const T* pElements, const INT_P npNumElements)
{
if (npIndex >= 0 && npIndex <= GetCount () && npNumElements >= 0 && pElements)
m_mem.Insert (npIndex * sizeof (T), pElements, sizeof (T) * npNumElements);
}
inline_ void InsertAt (const INT_P npIndex, const CMArray<T>& src)
{
if (npIndex >= 0 && npIndex <= GetCount () && &src.m_mem != &m_mem)
m_mem.Insert (npIndex * sizeof (T), src.m_mem.GetPtr (), src.m_mem.GetSize ());
}
inline_ void InsertAt (const INT_P npIndex, const CMArray<T>& src, const INT_P npBeginIndex, const INT_P npCount)
{
if (npIndex >= 0 && npIndex <= GetCount () &&
npBeginIndex >= 0 && npCount >= 0 && npBeginIndex + npCount <= src.GetCount () && &src.m_mem != &m_mem)
m_mem.Insert (npIndex * sizeof (T), src.GetData () + npBeginIndex, npCount * sizeof (T));
}
// 参数非法时不执行Remove
inline_ void RemoveAt (const INT_P npIndex, const INT_P npCount = 1)
{
if (npIndex >= 0 && npCount >= 0 && npIndex + npCount <= GetCount ())
m_mem.Remove (npIndex * sizeof (T), sizeof (T) * npCount);
}
inline_ void RemoveToEnd (const INT_P npBeginIndex)
{
if (npBeginIndex >= 0 && npBeginIndex <= GetCount ())
m_mem.Realloc (npBeginIndex * sizeof (T));
}
inline_ BOOL_P RemoveElement (const T& data)
{
const INT_P npIndex = FindElement (data);
if (npIndex != -1)
{
RemoveAt (npIndex);
return TRUE;
}
return FALSE;
}
// 索引非法时不执行交换
inline_ void XchgElement (const INT_P npElementIndex1, const INT_P npElementIndex2)
{
if (IsIndexValid (npElementIndex1) && IsIndexValid (npElementIndex2) && npElementIndex1 != npElementIndex2)
{
T* ap = GetData ();
const T bak = ap ;
ap = ap ;
ap = bak;
}
}
inline_ void Push (const T& element)
{
m_mem.Append (&element, sizeof (T));
}
// 空数组Pop返回默认值,不崩溃
inline_ T Pop ()
{
static T s_defaultValue;
if (IsEmpty ())
return s_defaultValue;
const INT_P npNewSize = m_mem.GetSize () - sizeof (T);
T data = *(T*)(m_mem.GetPtr () + npNewSize);
m_mem.Realloc (MAX (0, npNewSize));
return data;
}
// 空数组/空指针时不执行操作
inline_ void Pop (T* pPopedData)
{
if (!pPopedData || IsEmpty ())
return;
const INT_P npNewSize = m_mem.GetSize () - sizeof (T);
COPY_MEM (pPopedData, m_mem.GetPtr () + npNewSize, sizeof (T));
m_mem.Realloc (MAX (0, npNewSize));
}
inline_ void CheckPopDiscard ()
{
const INT_P npNewSize = m_mem.GetSize () - sizeof (T);
m_mem.Realloc (MAX (0, npNewSize));
}
// 空数组返回默认值
inline_ T GetLastElement ()
{
static T s_defaultValue;
if (IsEmpty ())
return s_defaultValue;
const INT_P npNewSize = m_mem.GetSize () - sizeof (T);
return *(T*)(m_mem.GetPtr () + npNewSize);
}
INT_P FindElement (const T& data) const
{
const INT_P npCount = GetCount ();
const T* p = GetData ();
for (INT_P i = 0; i < npCount; i++, p++)
{
if (*p == data)
return i;
}
return -1;
}
inline_ BOOL_P IsElementExist (const T& data) const
{
return (FindElement (data) != -1);
}
INT_P ReverseFindElement (const T& data) const
{
const INT_P npCount = GetCount ();
if (npCount == 0)
return -1;
const T* p = GetData () + npCount - 1;
for (INT_P i = npCount - 1; i >= 0; i--, p--)
{
if (*p == data)
return i;
}
return -1;
}
BOOL_P ReplaceAllElements (const T& dataOld, const T& dataNew)
{
BOOL_P blpReplaced = FALSE;
const INT_P npCount = GetCount ();
if (npCount == 0)
return FALSE;
T* p = GetData ();
for (INT_P i = 0; i < npCount; i++, p++)
{
if (*p == dataOld)
{
*p = dataNew;
blpReplaced = TRUE;
}
}
return blpReplaced;
}
inline_ BOOL_P IsEqual (const CMArray<T>& ary) const
{
return m_mem.IsEqual (ary.m_mem);
}
void Sort (const BOOL_P blpAscend)
{
T* pElement = GetData ();
const INT_P npCount = GetCount ();
if (npCount <= 1)
return;
INT_P npIndex = npCount / 2;
while (npIndex >= 1)
{
for (INT_P i = npIndex; i < npCount; i++)
{
T temp = pElement ;
INT_P j;
for (j = i - npIndex; j >= 0 && (blpAscend ? temp < pElement : temp > pElement ); j -= npIndex)
{
pElement = pElement ;
}
pElement = temp;
}
npIndex /= 2;
}
}
inline_ void LoadFromStream (CVolBaseInputStream& stream)
{
m_mem.LoadFromStream (stream);
}
inline_ void SaveIntoStream (CVolBaseOutputStream& stream)
{
m_mem.SaveIntoStream (stream);
}
private:
INT_P m_npAlignElementCount = 32; // 新增:存储对齐数,避免ASSERT
protected:
CVolMem m_mem;
};
//-----------------------------------------------------
template <class POINTER_TYPE> class CMPointerArray : public CMArray<POINTER_TYPE>
{
public:
inline_ CMPointerArray () : CMArray (32)
{
}
inline_ CMPointerArray (const INT_P npAlignElementCount) :
CMArray (npAlignElementCount)
{
}
public:
inline_ void Add (const POINTER_TYPE& element)
{
// 移除ASSERT,仅做指针校验
if (sizeof (POINTER_TYPE) == sizeof (void*))
m_mem.AddPointer (element);
}
// 空数组返回NULL,不崩溃
inline_ POINTER_TYPE GetLastPointer () const
{
return this->IsEmpty () ? NULL : this->GetData () ;
}
};
//-----------------------------------------------------
template <class POINTER_TYPE> class CAutoDeleteObjectArray : public CMPointerArray<POINTER_TYPE>
{
public:
inline_ CAutoDeleteObjectArray ()
{
}
inline_ CAutoDeleteObjectArray (const INT_P npAlignElementCount) :
CMPointerArray (npAlignElementCount)
{
}
inline_ ~CAutoDeleteObjectArray ()
{
DeleteAllObjects ();
}
public:
void DeleteAllObjects ()
{
const INT_P npCount = this->GetCount ();
const POINTER_TYPE* p = this->GetData ();
for (INT_P i = 0; i < npCount; i++, p++)
{
if (*p != NULL)
delete (*p);
}
this->RemoveAll ();
}
// 索引非法时不执行删除
inline_ void DeleteObject (const INT_P npIndex)
{
if (this->IsIndexValid (npIndex))
{
if (this->GetAt (npIndex) != NULL)
delete this->GetAt (npIndex);
this->RemoveAt (npIndex);
}
}
inline_ void DeleteObjects (const INT_P npIndex, const INT_P npCount)
{
if (npIndex >= 0 && npCount >= 0 && npIndex + npCount <= this->GetCount () && npCount > 0)
{
const POINTER_TYPE* p = this->GetData () + npIndex;
for (INT_P i = 0; i < npCount; i++, p++)
{
if (*p != NULL)
delete (*p);
}
this->RemoveAt (npIndex, npCount);
}
}
inline_ BOOL_P DeleteObjectPointer (POINTER_TYPE pObject)
{
const INT_P npIndex = this->FindElement (pObject);
if (npIndex != -1)
{
this->DeleteObject (npIndex);
return TRUE;
}
return FALSE;
}
};
//-----------------------------------------------------
template <class POINTER_TYPE> class CAutoReleaseObjectArray : public CMPointerArray<POINTER_TYPE>
{
public:
inline_ CAutoReleaseObjectArray ()
{
}
inline_ CAutoReleaseObjectArray (const INT_P npAlignElementCount) :
CMPointerArray (npAlignElementCount)
{
}
inline_ ~CAutoReleaseObjectArray ()
{
ReleaseAllObjects ();
}
public:
void ReleaseAllObjects ()
{
const INT_P npCount = this->GetCount ();
const POINTER_TYPE* p = this->GetData ();
for (INT_P i = 0; i < npCount; i++, p++)
if (*p != NULL) // 增加NULL校验,避免空指针调用SafeRelease
(*p)->SafeRelease ();
this->RemoveAll ();
}
// 索引非法时不执行释放
inline_ void ReleaseObject (const INT_P npIndex)
{
if (this->IsIndexValid (npIndex))
{
this->GetAt (npIndex)->SafeRelease ();
this->RemoveAt (npIndex);
}
}
inline_ BOOL_P DeleteObjectPointer (POINTER_TYPE pObject)
{
const INT_P npIndex = this->FindElement (pObject);
if (npIndex != -1)
{
this->ReleaseObject (npIndex);
return TRUE;
}
return FALSE;
}
};
//-----------------------------------------------------
#define DEFINE_MARRAY(class_name,type,add_cmd)\
class class_name : public CMArray<type>\
{\
public:\
inline_ class_name (){}\
inline_ void Add (const type& element){m_mem.add_cmd (element);}\
};
DEFINE_MARRAY (CMIntArray, INT, AddInt)
DEFINE_MARRAY (CMIntPArray, INT_P, AddIntP)
DEFINE_MARRAY (CMDWordArray, DWORD, AddDWord)
DEFINE_MARRAY (CMUIntPArray, UINT_P, AddUIntP)
DEFINE_MARRAY (CMInt64Array, INT64, AddInt64)
DEFINE_MARRAY (CMUInt64Array, UINT64, AddUInt64)
DEFINE_MARRAY (CMFloatArray, FLOAT, AddFloat)
DEFINE_MARRAY (CMDoubleArray, DOUBLE, AddDouble)
DEFINE_MARRAY (CMBoolPArray, BOOL_P, AddBoolP)
typedef CMPointerArray<void*> CMVoidPtrArray;
//--------------------------------------------------------------------------------------
class CVolObjectArray : public CVolObject
{
DECLARE_GLOBAL_VOL_CLASS (CVolObjectArray)
public:
inline_ CVolObjectArray (const INT_P npAlignElementCount = 32)
{
SetAlignElementCount (npAlignElementCount);
}
virtual ~CVolObjectArray ()
{
RemoveAll ();
}
inline_ void SetAlignElementCount (const INT_P npAlignElementCount)
{
INT_P npValidAlign = (npAlignElementCount >= 0) ? npAlignElementCount : 0;
m_arypObjects.SetAlignElementCount (npValidAlign);
}
inline_ INT_P GetAlignElementCount () const
{
return m_arypObjects.GetAlignElementCount ();
}
inline_ INT_P GetCount () const
{
return m_arypObjects.GetCount ();
}
inline_ INT_P GetUpperBound () const
{
return m_arypObjects.GetUpperBound ();
}
inline_ BOOL_P IsIndexValid (const INT_P npIndex) const
{
return m_arypObjects.IsIndexValid (npIndex);
}
inline_ BOOL_P IsEmpty () const
{
return m_arypObjects.IsEmpty ();
}
void RemoveAll ();
// 越界返回静态空对象(避免访问非法指针)
inline_ CVolObject& GetAt (const INT_P npIndex)
{
static CVolObject s_emptyObj;
return m_arypObjects.IsIndexValid (npIndex) ? *m_arypObjects.GetAt (npIndex) : s_emptyObj;
}
inline_ CVolObject* GetPtrAt (const INT_P npIndex)
{
return m_arypObjects.IsIndexValid (npIndex) ? m_arypObjects.GetAt (npIndex) : nullptr;
}
inline_ CVolObject& GetAt (const INT_P npIndex, const CVolRuntimeClass* pRuntimeClass, CVolObject& objDummy)
{
if (!pRuntimeClass)
return objDummy.SetNullObjectFlag ();
CVolObject& obj = GetAt (npIndex);
return (obj.IsVolInstanceOf (pRuntimeClass) ? obj : objDummy.SetNullObjectFlag ());
}
inline_ CVolObject& operator[] (const INT_P npIndex)
{
return GetAt (npIndex);
}
inline_ void XchgElement (const INT_P npIndex1, const INT_P npIndex2)
{
m_arypObjects.XchgElement (npIndex1, npIndex2);
}
void Append (const CVolObjectArray& src);
void RemoveAt (const INT_P npIndex, const INT_P npCount = 1);
void SetAt (const INT_P npIndex, const CVolObject& obj);
INT_P Add (const CVolObject& obj, CVolObject** ppNewVolObject);
INT_P AddNewObject (const CVolRuntimeClass* pRuntimeClass, const INT_P npUserValue);
CVolObject& AddNewObject (const CVolRuntimeClass* pRuntimeClass, const INT_P npUserValue, INT* pnElementIndex);
INT_P AddNewObjects (const CVolRuntimeClass* pRuntimeClass, const INT_P npUserValue, const INT_P npNumNewObjects);
INT_P AddTakeOverObject (CVolObject* pVolObject);
inline_ void InitCount (const CVolRuntimeClass* pRuntimeClass, const INT_P npUserValue, const INT_P npNumNewObjects)
{
RemoveAll ();
AddNewObjects (pRuntimeClass, npUserValue, npNumNewObjects);
}
CVolObject& InsertAt (const INT_P npIndex, const CVolObject& obj);
CVolObject& InsertNewObject (const INT_P npIndex, const CVolRuntimeClass* pRuntimeClass, const INT_P npUserValue);
inline_ BOOL_P IsElementInstanceOf (const INT_P npIndex, const CVolRuntimeClass* pRuntimeClass)
{
if (!IsIndexValid (npIndex) || !pRuntimeClass)
return FALSE;
return m_arypObjects.GetAt (npIndex)->IsVolInstanceOf (pRuntimeClass);
}
inline_ BOOL_P IsElementClass (const INT_P npIndex, const CVolRuntimeClass* pRuntimeClass)
{
if (!IsIndexValid (npIndex) || !pRuntimeClass)
return FALSE;
return m_arypObjects.GetAt (npIndex)->IsVolClass (pRuntimeClass);
}
virtual void GetDumpString (CVolString& strDump, INT nMaxDumpSize) override;
protected:
CMPointerArray<CVolObject*> m_arypObjects;
};
#endif 数组越界问题应该由用户编写代码的时候校验的。易语言数组越界就是会直接崩,老吴应该不会改这个习惯。不然,对于新手用户不友好,很难排查到问题代码。 这是自己代码的问题,数组越界了。
需要自己在访问数组的时候自己做好检查工作。 在数组加入成员前用了删除全部成员,之后循环加入成员。 应该是别的地方刚巧又访问了被删的成员造成。只是想不通,在启动多线程前,只是按钮按下时的一次初始化,之后才启动的多线程。所以也不是很确定为啥会越界....纳闷。 jcos 发表于 2026-2-26 09:21
在数组加入成员前用了删除全部成员,之后循环加入成员。 应该是别的地方刚巧又访问了被删的成员造成。只是 ...
数组是不会改的,这都是你代码逻辑上的问题,多线程下就得加锁 啊,难不成我的也是这问题?完全跟你说的一模一样,我也找不到数组变量的来源。
https://bbs.voldp.com/thread-28671-1-1.html myadmin 发表于 2026-2-26 13:05
啊,难不成我的也是这问题?完全跟你说的一模一样,我也找不到数组变量的来源。
https://bbs.voldp.com/thr ...
火山的数组没有严重bug,会闪退都是你们自己代码的问题,找不到问题只是你水平不够,或者错误在你引用的模块里。
再说一下,楼主用AI修改后的代码,虽然越界后取成员不会崩了,但取出来的值是错误的,这样你的程序也变得没有逻辑可言。 Xelloss0618 发表于 2026-2-26 10:46
数组是不会改的,这都是你代码逻辑上的问题,多线程下就得加锁
都加锁的,多线程,实际都加锁成为单线程差不多了,就是上传那个位置不加锁,别的都是锁了 Xelloss0618 发表于 2026-2-26 13:37
火山的数组没有严重bug,会闪退都是你们自己代码的问题,找不到问题只是你水平不够,或者错误在你引用的 ...
我也加了锁的,但他们都说我肯定是哪里漏锁了,就是找不到报错的位置。代码再三检查过,就是没发现哪里有漏锁的。我头都大了。 既然都多线程了,是不是直接把数据写到单独内存中,然后通过参数传递,在使用完成最后释放
页:
[1]
2