可变大小的类 - C++

发布于 2024-07-12 01:02:58 字数 413 浏览 7 评论 0原文

我见过一个类,它是这样定义的。

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

拿命拼未来 2024-07-19 01:02:58

这是一个古老的 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.

泛泛之交 2024-07-19 01:02:58

如果 iBuf 是结构的最后一个成员,这对于 POD 来说应该没问题。 非 POD 的问题可能是,例如。 编译器可以自由地重新排序公共/私有/受保护的成员,虚拟基类最终出现在最派生的对象 IIUC 的末尾,等等。

您的结构是非 POD(它有一个基类),所以我不推荐它。

另外,如果你创建这样的实例,

return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();

你应该确保 malloc 获取的内存应该用 free 释放,所以像这样删除你的实例:

obj->~StringChild();
free(obj);

也许你想使用 ::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

return new(malloc(__builtin_offsetof(StringChild ,iBuf[size]))) StringChild();

You should make sure that memory acquired by malloc should be freed with free, so delete your instances like this:

obj->~StringChild();
free(obj);

Maybe you'd like to use ::operator new() for allocation

︶葆Ⅱㄣ 2024-07-19 01:02:58

严格来说,由于 StringChild 是从 StringBase 派生的,因此它并不安全。 C++ 标准没有指定基类子对象的布局。 第 10 条第 3 款:

未指定基类子对象在最派生对象 (1.8) 中分配的顺序。

如果 StringChild 是 POD 结构,那么这种技术就是安全的。

Strictly speaking, since StringChild is derived from StringBase it's not safe. The C++ standard does not specify the layout for base class subobjects. Clause 10 Paragraph 3:

The order in which the base class subobjects are allocated in the most derived object (1.8) is unspecified.

If StringChild were a POD struct, then such a technique would be safe.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文