2

I have seen a great answer here which has helped me to a great extent (Proper way to create unique_ptr that holds an allocated array) but I still have an issue.

Code:

void CSelectedBroHighlight::BuildSelectedArray()
{
    CString     strText;
    
    // empty current array
    m_aryStrSelectedBro.RemoveAll();
    
    // get selected count
    const auto iSize = m_lbBrothers.GetSelCount();
    if(iSize > 0)
    {
        //auto pIndex = std::make_unique<int[]>(iSize);

        auto pIndex = new int[iSize];
        m_lbBrothers.GetSelItems(iSize, pIndex);
        
        for(auto i = 0; i < iSize; i++)
        {
            m_lbBrothers.GetText(pIndex[i], strText);
            m_aryStrSelectedBro.Add(strText);
        }
        
        delete[] pIndex;
    }
}

If I turn pIndex into a smart pointer:

auto pIndex = std::make_unique<int[]>(iSize);

So that I don't need the delete[] pIndex; call. Then I can't pass pIndex to GetSelItems. I can pass pIndex.release() here but then we have a problem for deleting again.

  • I have looked at this discussion (Issue passing std::unique_ptr's) but we don't want to pass ownership.
  • If I simplify this and declar my variable: auto pIndex = std::make_unique<int[]>(iSize).release(); then I can pass it, but now have the issue of calling delete[] pIndex;.

Whats correct?

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164

1 Answers1

3

If you need access to the pointer to an object managed by a std::unique_ptr without transferring ownership, you can call its get() method. This is useful for interop with a C interface such as here (GetSelItems() is really just wrapping a call to SendMessage with the LB_GETSELITEMS message).

That'd work, though in this case I'd probably use a std::vector<int> instead. It provides the same properties as a std::unique_ptr with respect to automatic cleanup, but also has other features that come in handy (specifically range adapters). It also feels more natural to use a container here, but that's a matter of personal preference.

The following implements the proposed changes:

void CSelectedBroHighlight::BuildSelectedArray() {
    // empty current array
    m_aryStrSelectedBro.RemoveAll();
    
    // get selected count
    auto const sel_item_count{ m_lbBrothers.GetSelCount() };
    if(sel_item_count > 0) {
        // get selected indices
        std::vector<int> sel_items(sel_item_count);
        m_lbBrothers.GetSelItems(sel_items.size(), sel_items.data());
        
        // iterate over all selected item indices
        for(auto const index : sel_items) {
            CString strText;
            m_lbBrothers.GetText(index, strText);
            m_aryStrSelectedBro.Add(strText);
        }
    }
}

This provides the same automatic cleanup as an implementation based on std::unique_ptr, but also enables use of a range-based for loop further down.

IInspectable
  • 46,945
  • 8
  • 85
  • 181