Search code examples
arraysvisual-c++mfcgsl

Problem using gsl::span with a dynamic list of CStringArray objects is causing a abort


See this code:

if (pAryStrCustom != nullptr)
{
    const gsl::span spanAryStrCustom(pAryStrCustom, pAryStrCustom->GetSize());
    uStartIndex = FILLED_COLUMN_INDEX_MIKE +
        rsRowData.uNumMikesToFill + rsRowData.uNumAttendToFill;
    for (uAssign = 0; uAssign < rsRowData.uNumCustomToFill; uAssign++, uStartIndex++)
    {
        if (!IsReadOnly(rsRowData.uGridRow, rsRowData.aryUICustomColIndex[uAssign]))
        {
            // Only auto assign custom cells that are COMBO (ie: NOT read only)
            //if (!AutoAssign(1, uStartIndex, spanAryStrCustom[uAssign],
            //  rsRowData, rsRowData.aryUICustomColIndex[uAssign]))
            if (!AutoAssign(1, uStartIndex, pAryStrCustom[uAssign],
                rsRowData, rsRowData.aryUICustomColIndex[uAssign]))
            {
                bOK = FALSE;
            }
        }
        else
        {
            // Blank out name
            rsRowData.pAryStrNamesThisRow->SetAt(uStartIndex, _T(""));
        }
    }
}

This is how the main variable (pAryStrCustom) is defined:

CStringArray* CCreateReportDlg::BuildCustomAssignArray(const ROW_DATA_S &rsRowData)
{
    CStringArray    *pAryStrCustom = nullptr;

    if (rsRowData.uNumCustomToFill > 0)
    {
        pAryStrCustom =std::make_unique<CStringArray[]>(rsRowData.uNumCustomToFill).release();
        ASSERT(pAryStrCustom != nullptr);
        if (pAryStrCustom == nullptr)
            return nullptr;

        const gsl::span spanAryStrCustom(pAryStrCustom, rsRowData.uNumCustomToFill);

        const auto iNumAssigns = m_aryPtrAssign.GetSize();
        for (INT_PTR iAssign = 0, iUsedAssign = 0; iAssign < iNumAssigns; iAssign++)
        {
            const CUSTOM_ASSIGN_S* psAssign = static_cast<CUSTOM_ASSIGN_S*>(m_aryPtrAssign.GetAt(iAssign));
            if (psAssign != nullptr)
            {
                if (!psAssign->bExcluded && iUsedAssign < gsl::narrow<INT_PTR>(rsRowData.uNumCustomToFill))
                {
                    spanAryStrCustom[iUsedAssign].Copy(psAssign->aryStrBrothersAll);
                    iUsedAssign++;
                }
            }
        }
    }

    return pAryStrCustom;
}

I have debugged my code and I have an array of 5 CStringArrays. And each of the arrays do have content. But notice I had to comment out some code:

//if (!AutoAssign(1, uStartIndex, spanAryStrCustom[uAssign],
//  rsRowData, rsRowData.aryUICustomColIndex[uAssign]))

It dies if I use that spanAryStrCustom span. Why? Using a legacy array approach to access the data is fine.

This is the offending bit:

spanAryStrCustom[uAssign]

Solution

  • I had to change the way I defined the span:

    const gsl::span spanAryStrCustom(pAryStrCustom, rsRowData.uNumCustomToFill);
    

    It was a mistake to use pAryStrCustom->GetSize() because it is actually an dynamic array of CStringArray objects. I now realise that using GetSize() was returning the size of the first array (4) which was actually making it one smaller than it needed to be (5).

    So using the same UINT that was used to build the dynamic array was the answer.