0

我有一个数据缓冲区存储在shared_ptr<void>.

这个缓冲区被组织在几个封装层中,所以我最终得到:

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

(实际上它是一个以太网数据包,我在其中逐层解封装)。

一旦我读取了 Header 1,我想将数据包的其余部分传递给下一层进行读取,所以我想创建一个指向:

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

使用原始指针将非常容易,因为它只是指针算术的问题。但是我怎样才能用 shared_ptr 实现呢?(我使用 boost::shared_ptr):

  • 我无法为“第一个 shared_ptr.get() + offset”创建一个新的 shared_ptr,因为将所有权归于公正是没有意义的Header 2 + Data(并且 delete 最终会崩溃)
  • 我不想复制数据,因为它会很傻
  • 我希望在两个对象之间共享整个缓冲区的所有权(即,只要父对象或仅需要 Header 2 的对象需要数据,则不应删除数据)。

我可以把它包装成这样的结构,boost::tuple<shared_ptr<void>, int /*offset*/, int /*length*/>但我想知道是否有更方便/优雅的方式来实现这一结果。

谢谢,

4

3 回答 3

1

我建议将每个层封装在一个知道如何处理数据的类中,就好像它是那个层一样。将每一个都视为缓冲区的视图。这是一个让你思考的起点。

class Layer1{
public:
    Layer1(shared_ptr<void> buffer) : buffer_(buffer) { }

   /* All the functions you need for treating your buffer as a Layer 1 type */
    void DoSomething() {}

private:
   shared_ptr<void> buffer_;
};

class Layer2{
public:
    Layer2(shared_ptr<void> buffer) : buffer_(buffer) { }

   /* All the functions you need for treating your buffer as a Layer 2 type */
    void DoSomethingElse() {}

private:
   shared_ptr<void> buffer_;
};

以及如何使用它:

shared_ptr<void> buff = getBuff(); //< Do what you need to get the raw buffer.

// I show these together, but chances are, sections of your code will only need
// to think about the data as though it belongs to one layer or the other.
Layer1 l1(buff);
Layer2 l2(buff);

l1.DoSomething();
l2.DoSomethingElse();

以这种方式布局允许您编写仅在该层上运行的函数,即使它们在内部表示相同的数据。

但是,这绝不是完美的。

也许 Layer2 应该能够调用 Layer1 的方法。为此,您也需要继承。我对您的设计知之甚少,无法说出这是否有帮助。其他改进的空间是用shared_ptr<void>一个具有处理缓冲区的有用方法的类来替换。

于 2012-11-28T21:33:26.297 回答
0

你能用一个简单的包装器吗?

像这样的东西?

class HeaderHolder : protected shared_ptr<void> {
public:
    // Constructor and blah blah

    void* operator* () {
        offset += a_certain_length;
        return (shared_ptr<void>::operator*() + offset);
    }
};
于 2012-11-28T21:08:40.107 回答
0

顺便说一句,我只是使用了一个简单的包装器,如果有人偶然发现这个问题,我会在这里复制它。

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;
};

使用 GetData 时要小心:确保在使用不安全的 void* 时不会释放缓冲区。只要您知道 DataWrapper 对象是活动的,使用 void* 是安全的(因为它在缓冲区中保存了一个 shared_ptr,因此它可以防止它被释放)。

于 2012-12-20T13:43:42.027 回答