shared_ptr的子数据(类似于?的子字符串)

Subdata (substring-like?) of a shared_ptr

本文关键字:字符串 类似于 数据 ptr shared      更新时间:2023-10-16

我在shared_ptr<void>中存储了一个数据缓冲区。

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

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

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

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

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

使用原始指针会非常容易,因为这只是指针算术的问题。但是,我如何使用shared_ptr来实现这一点呢?(我使用boost::shared_ptr):

  • 我无法创建一个新的shared_ptr到"first shared_ptr.get()+offset",因为只将所有权分配给Header 2 + Data是没有意义的(删除最终会崩溃)
  • 我不想复制这些数据,因为那样会很傻
  • 我希望整个缓冲区的所有权在两个对象之间共享(即,只要父对象或只需要Header 2的对象需要数据,就不应该删除数据)

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

谢谢,

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

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>

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

也许是这样的?

class HeaderHolder : protected shared_ptr<void> {
public:
// Constructor and blah blah
void* operator* () {
offset += a_certain_length;
return (shared_ptr<void>::operator*() + offset);
}
};

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

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,所以它可以防止它被释放)。