Search code examples
c++boostshared-ptr

Subdata (substring-like?) of a shared_ptr


I have a data buffer stored in a shared_ptr<void>.

This buffer is organized in several encapsulated layers so that I end up with:

-----------------------------------...
- Header 1 | Header 2 | Data
-----------------------------------...

(Actually it's an Ethernet packet where I decapsulate the layers one after the other).

Once I read Header 1, I would like to pass the rest of the packet to the next layer for reading, so I would like to create a pointer to :

-----------------------...
- Header 2 | Data
-----------------------...

It would be very easy with a raw pointer, as it would just be a matter of pointer arithmetic. But how can I achieve that with a shared_ptr ? (I use boost::shared_ptr) :

  • I cannot create a new shared_ptr to "first shared_ptr.get() + offset" because it makes no sense to get the ownership to just Header 2 + Data (and delete would crash eventually)
  • I do not want to copy the data because it would be silly
  • I want the ownership on the whole buffer to be shared between the two objects (ie. as long as the parent object or the one which requires only Header 2 needs the data, the data should not be deleted).

I could wrap that up in a structure like boost::tuple<shared_ptr<void>, int /*offset*/, int /*length*/> but I wonder if there is a more convenient / elegant way to achieve that result.

Thanks,


Solution

  • By the way, I just used a simple wrapper that I reproduce here if someone ever stumbles on the question.

    class DataWrapper {
    public:
        DataWrapper (shared_ptr<void> pData, size_t offset, size_t length) : mpData(pData), mOffset(offset), mLength(length) {}
    
        void* GetData() {return (unsigned char*)mpData.get() + mOffset;}
        // same with const...
        void SkipData (size_t skipSize) { mOffset += skipSize; mLength -= skipSize; }
        void GetLength const {return mLength;}
    
        // Then you can add operator+, +=, (void*), -, -=
        // if you need pointer-like semantics.
        // Also a "memcpy" member function to copy just this buffer may be useful
        // and other helper functions if you need
    
    private:
        shared_ptr<void> mpData;
        size_t mOffset, mLength;
    };
    

    Just be careful when you use GetData: be sure that the buffer will not be freed while you use the unsafe void*. It is safe to use the void* as long as you know the DataWrapper object is alive (because it holds a shared_ptr to the buffer, so it prevents it from being freed).