如何组合变长结构习语
struct Data
{
std::size_t size;
char data[];
};
使用make_shared成语基本上做同样的事情,这样我就可以将shared_ptr结束到一个连续的内存块,其中包含引用计数结构头和结构数据。
即。
之类的东西// allocate an extra 30 bytes for the data storage
shared_ptr<Data> ptr = allocate_shared<Data>( vls_allocator(30) );
答案 0 :(得分:1)
你可以使用boosts侵入式共享指针来实现这一点(不确定C ++ 11是否直接支持)。
http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/intrusive_ptr.html
你需要创建一个带有引用计数的更大的结构,而你的指针指向laregr结构而不是它包含的Data
成员。
您还需要将释放函数连接到这些指针。
注意:我怀疑有一些方法可以将共享指针放到Data
成员而不是包装器中 - 但是上次我用boost shared_ptr
代码执行此操作时,它需要一些有趣的黑客攻击。 / p>
答案 1 :(得分:0)
我认为这是一项重要的要求,尤其是在编写必须与低级系统功能交互或提供接口的代码时(现代C ++之外,但仍符合现代代码)。
解决方案分为两部分。首先,将缓冲区分配为智能指针,然后以安全的方式将其强制转换为正确的类型,以通过代码分析/准则检查器。
第二部分通常与“ std :: reinterpret_pointer_cast
在C ++ 20之前缺少链接的第一部分是创建到可变长度缓冲区的安全的shared_ptr,例如,由“ std :: make_shared
I stumbled upon this macro与std :: reinterpret_pointer_cast结合使用时,可以得到一个不错的“ polyfill”,以干净的代码实现相同的结果,直到C ++ 20普遍可用为止。
// C++20 polyfill for missing "make_shared<T[]>(size_t size)" overload.
template<typename T>
inline std::shared_ptr<T> make_shared_array(size_t bufferSize)
{
return std::shared_ptr<T>(new T[bufferSize], [](T* memory) { delete[] memory; });
}
// Creates a smart pointer to a type backed by a variable length buffer, e.g. system structures.
template<typename T>
inline std::shared_ptr<T> CreateSharedBuffer(size_t byteSize)
{
return std::reinterpret_pointer_cast<T>(make_shared_array<uint8_t>(byteSize));
}
示例:
size_t privilegesSize = sizeof(TOKEN_PRIVILEGES) + (sizeof(LUID_AND_ATTRIBUTES) * privilegesCount);
auto tokenPrivileges = CreateSharedBuffer<TOKEN_PRIVILEGES>(privilegesSize);
唯一的副作用显然是在分配过程中将进行第二次内存访问,但是考虑到C ++ 20即将来临,您的解决方案现在可以使用干净可靠的代码运行起来更加高效和健壮,而不必担心额外的处理器一两个周期就可以了。
在C ++ 20可用时,您要做的就是删除“ polyfill”模板,并将对它的调用从“ make_shared_array”重命名或替换为“ make_shared”(带有新的C ++ 20重载)。如果可以接受以下C ++ 20解决方案,则可以选择放弃整个CreateSharedBuffer宏:
auto data = std::reinterpret_cast<Data>(std::make_shared<uint8_t>(sizeof(Data) + (sizeof(char) * 30)));