可变大小的类 - C++
我见过一个类,它是这样定义的。
class StringChild : public StringBase
{
public:
//some non-virtual functions
static StringChild* CreateMe(int size);
private:
unsigned char iBuf[1];
};
静态工厂函数具有以下实现。
return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();
据我所知,该函数使用新的放置来扩展此类。
这是否安全只是因为只有 1 个成员并且它分配在堆上?
I've seen a class which is a class which is defined like this..
class StringChild : public StringBase
{
public:
//some non-virtual functions
static StringChild* CreateMe(int size);
private:
unsigned char iBuf[1];
};
The static factory function has the following implementation..
return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();
So as far as I understand it this function is using placement new to extend this class.
Is this safe only because there is only 1 member and it's allocated on the heap?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是一个古老的 C 技巧,用于解决普通 C 中可变长度数组不可用的问题。是的,只要您使用合适的分配器结构(例如分配一堆所需大小的原始内存和然后将新对象放置在那里)。 只要您不徘徊在分配的内存末尾,它就是安全的,但它确实会使至少一些内存调试器感到困惑。
使用此技术时必须绝对确定的一件事是可变长度数组是对象布局中的最后一个元素,否则您将遍历其他内部变量。
然而,我对工厂函数的实现有点怀疑 - 我假设“size”参数实际上是所需的数组大小? 另外,不要忘记,您必须使用“释放”而不是“删除”来释放上面的内存,尽管后者在大多数情况下可能有效。
除非有令人信服的理由说明为什么必须以这种方式管理内存,否则我会简单地将数组替换为 std::vector 。
It's an old C trick that was used to work around the non-availablity of variable length arrays in plain C. Yes, it also works in C++ as long as you use suitable allocator constructs (like allocating a bunch of raw memory the desired size and then placement newing the object in there). It's safe as long as you don't wander over the end of the allocated memory, but it does tend to confuse at least some memory debuggers.
One thing you have to make absolutely certain when using this technique is that the variable length array is the last element in the object layout, otherwise you'll walk over other internal variables.
I am however a little dubious about the implementation of the factory function - I assume the 'size' parameter is actually the desired array size? Also, don't forget that you'd have to release the memory above using 'free' and not 'delete', even though the latter might work in most cases.
Unless there's a compelling reason as to why the memory has to be managed this way, I would simply replace the array with a std::vector.
如果 iBuf 是结构的最后一个成员,这对于 POD 来说应该没问题。 非 POD 的问题可能是,例如。 编译器可以自由地重新排序公共/私有/受保护的成员,虚拟基类最终出现在最派生的对象 IIUC 的末尾,等等。
您的结构是非 POD(它有一个基类),所以我不推荐它。
另外,如果你创建这样的实例,
你应该确保 malloc 获取的内存应该用 free 释放,所以像这样删除你的实例:
也许你想使用
::operator new()
用于分配This should be OK for PODs provided iBuf is the last member of the structure. The problems with non-PODs could be that eg. compiler is free to reorder public/private/protected members, virtual base classes end up at the end of the most derived object IIUC, etc.
Your structure is non-POD (it has a base class) so I wouldn't recommend it.
Also, if you create instances like this
You should make sure that memory acquired by malloc should be freed with free, so delete your instances like this:
Maybe you'd like to use
::operator new()
for allocation严格来说,由于
StringChild
是从StringBase
派生的,因此它并不安全。 C++ 标准没有指定基类子对象的布局。 第 10 条第 3 款:如果 StringChild 是 POD 结构,那么这种技术就是安全的。
Strictly speaking, since
StringChild
is derived fromStringBase
it's not safe. The C++ standard does not specify the layout for base class subobjects. Clause 10 Paragraph 3:If
StringChild
were a POD struct, then such a technique would be safe.