1

我见过一个类是这样定义的类..

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();

据我了解,这个函数使用placement new 来扩展这个类。

这是否只是因为只有 1 个成员并且它是在堆上分配的?

4

3 回答 3

6

这是一个古老的 C 技巧,用于解决普通 C 中可变长度数组不可用的问题。是的,只要您使用合适的分配器构造(例如分配一堆原始内存所需的大小和然后将新对象放置在那里)。只要您不徘徊在分配内存的末尾,它就是安全的,但它确实往往会混淆至少一些内存调试器。

使用此技术时您必须绝对确定的一件事是可变长度数组是对象布局中的最后一个元素,否则您将遍历其他内部变量。

然而,我对工厂函数的实现有点怀疑——我假设“大小”参数实际上是所需的数组大小?另外,不要忘记你必须使用'free'而不是'delete'来释放上面的内存,即使后者在大多数情况下可能工作。

除非有令人信服的理由说明为什么必须以这种方式管理内存,否则我会简单地将数组替换为 std::vector。

于 2009-01-09T11:46:30.270 回答
3

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

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

此外,如果您创建这样的实例

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

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

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

也许您想::operator new()用于分配

于 2009-01-09T12:01:06.700 回答
0

严格来说,sinceStringChild是从它衍生而来的,StringBase它是不安全的。C++ 标准没有指定基类子对象的布局。第 10 条第 3 款:

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

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

于 2009-01-09T12:04:55.193 回答