1

How would you create a generic buffer or array type template (not using STL) that may be used on a struct type that includes a class or non-trivial type. Something this, which uses memcpy and such which may not be appropriate.

template<class T>
class CGrowableBuffer
{

protected:
    T* m_pBuff;
    unsigned m_nSize;
    unsigned m_nCount;
    unsigned m_nGrowBy;
};
 
// ... 
    
template<class T>
IBOOL CGrowableBuffer<T>::Insert(const T* p, unsigned index, unsigned count)
{
  if (index>m_nCount || !SetSize(m_nCount + count))
    return FALSE;
  memmove(m_pBuff+index+count, m_pBuff+index, (m_nCount-index)*sizeof(T));
  if (p==NULL) {
    memset(m_pBuff + index, 0, count * sizeof(T));
  }
  else {
    memcpy(m_pBuff + index, p, count * sizeof(T));
  }
  m_nCount += count;
  return TRUE;
}

// ...    
15
  • 5
    I would look at the implementation of std::vector and copy that. But why are you trying to reinvent the wheel? Commented Aug 19 at 0:41
  • So this boils down to making a home-made vector class? If so, there are tons of them written and readily available. Commented Aug 19 at 0:48
  • @catnip it existed before STL and doesn't bloat the apps. Commented Aug 19 at 1:04
  • 1
    The only reason I see NOT to use std::vector is if you are doing a homework assignment (if so mention it in your question). In all other cases use tested code (like the standard library) and focus on the writing code that solves your specific requirements. Also whenever you start growing a vector you will get memory fragmentation, I think you mean "contiguous" memory for your data. Commented Aug 19 at 3:22
  • 1
    it existed before STL and doesn't bloat the apps How much work would it be to update your codebase to use std::vector? Your future self (and any co-workers) will thank you for it. As for code bloat, std::vector should be no more expensive than any replacement you might write for it. Commented Aug 19 at 7:22

1 Answer 1

1

There are standard library template functions to move and/or copy objects which you would use instead of memcpy and memmove. These functions will deal with non-trivial classes and are specialized to optimize the trivial cases.

In the case of your Insert() method above, I'd start by allocating raw memory to the new size then use std::unitialized_move to copy the current objects into the new memory. Use std::construct_at to initialize the new items being inserted. Then use std::destroy to uninitialize the original objects before freeing the memory.

I've always done it with raw memory, but you could also use a typed array with new/delete and then use std::copy, or std::move, and let the array destroy itself. But you'd suffer performance wise with extra constructor calls. That might not matter to you though.

    // Ignoring your growby and error handling for now
    T* buffer = reintepret_cast<T*>(std::malloc(sizeof(T) * (m_nCount + count)));
    std::uninitialized_move(m_pBuff, m_pBuff + index, buffer);
    std::uninitialized_move(m_pBuff + index, m_pBuff + m_nCount,buffer + index + count);
    while (count)
        std::construct_at(buffer + index + --count);
    std::destroy(m_pBuff, m_pBuff + m_nCount);
    std::free(m_pBuff);
    m_pBuff = buffer;
    m_nCount += count;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.