Variable-size object 在 shared_ptr
Variable-size object in shared_ptr
假设我想要一个 variable-size 数组,前面有一点 header 存储在 std::shared_ptr
中。我可以做类似
的事情
#include <memory>
using namespace std;
struct obj {
char headerCode;
unique_ptr<short[]> data;
};
shared_ptr<obj> make(unsigned len) {
return shared_ptr<obj>{new obj{'x', unique_ptr<short[]>{new short[len]}}};
}
但这会导致三种分配:一种用于 shared_ptr
控制块,一种用于 obj
,一种用于其 data
。使用 make_shared
前两个可能共享一些内存:
#include <memory>
using namespace std;
struct obj {
char headerCode;
unique_ptr<short[]> data;
obj(char headerCode, short data[]) : headerCode(headerCode), data(data) {}
};
shared_ptr<obj> make(unsigned len) {
return make_shared<obj>('x', new short[len]);
}
通过 low-level 分配,我可以使 object 及其数据共享一些内存:
#include <memory>
#include <cstdlib>
using namespace std;
struct obj {
char headerCode;
short data[0];
};
shared_ptr<obj> make(unsigned len) {
obj* o = reinterpret_cast<obj*>(malloc(sizeof(obj) + len*sizeof(short)));
o->headerCode = 'x';
return shared_ptr<obj>(o, free);
}
标准允许使用这两种技术吗?如果不是,是否有类似的东西是允许的?有没有什么东西可以让这项工作以 standards-conforming 的方式只用一次内存分配?最好不必在每个实例中都存储分配器或删除器 object?
Are these two techniques allowed by the standard?
第一个很好,第二个使用零长度数组作为成员 (data[0]
),这不是有效的 C++,但作为扩展被某些编译器支持。
Is there something which makes this work in a standards-conforming way with only a single memory allocation?
目前,如果没有 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3641.html,这将非常困难,这将允许这样的事情:
struct obj {
char headerCode;
short* data;
};
shared_ptr<obj> make(unsigned len) {
auto p = make_shared<char[]>(sizeof(obj) + sizeof(short)*len));
short* s = static_cast<short*>(p.get() + sizeof(obj));
return shared_ptr<obj>(p, ::new(p.get()) obj{'x', s});
}
这分配了一个 char
的数组,其中 space 足够 obj
和 short
的数组,然后使用新的放置来构造一个 obj
到那个内存中,并创建另一个 shared_ptr
与拥有 char
数组的那个共享所有权。当拥有内存的最后一个 shared_ptr
删除它的引用时,char
数组将被正确删除,但 obj
对象的析构函数不会是 运行,所以重要的是你不要依赖它的析构函数有任何副作用(理想情况下它会有一个微不足道的析构函数)。
您今天可以使用 allocate_shared
和自定义分配器来完成此操作,该分配器会为 short
的数组分配额外的 space,但由于您不知道如何实现会将控制块和您的对象安排在 space 分配中很难计算出 short
数组的开始位置,分配器需要存储在控制块中。
假设我想要一个 variable-size 数组,前面有一点 header 存储在 std::shared_ptr
中。我可以做类似
#include <memory>
using namespace std;
struct obj {
char headerCode;
unique_ptr<short[]> data;
};
shared_ptr<obj> make(unsigned len) {
return shared_ptr<obj>{new obj{'x', unique_ptr<short[]>{new short[len]}}};
}
但这会导致三种分配:一种用于 shared_ptr
控制块,一种用于 obj
,一种用于其 data
。使用 make_shared
前两个可能共享一些内存:
#include <memory>
using namespace std;
struct obj {
char headerCode;
unique_ptr<short[]> data;
obj(char headerCode, short data[]) : headerCode(headerCode), data(data) {}
};
shared_ptr<obj> make(unsigned len) {
return make_shared<obj>('x', new short[len]);
}
通过 low-level 分配,我可以使 object 及其数据共享一些内存:
#include <memory>
#include <cstdlib>
using namespace std;
struct obj {
char headerCode;
short data[0];
};
shared_ptr<obj> make(unsigned len) {
obj* o = reinterpret_cast<obj*>(malloc(sizeof(obj) + len*sizeof(short)));
o->headerCode = 'x';
return shared_ptr<obj>(o, free);
}
标准允许使用这两种技术吗?如果不是,是否有类似的东西是允许的?有没有什么东西可以让这项工作以 standards-conforming 的方式只用一次内存分配?最好不必在每个实例中都存储分配器或删除器 object?
Are these two techniques allowed by the standard?
第一个很好,第二个使用零长度数组作为成员 (data[0]
),这不是有效的 C++,但作为扩展被某些编译器支持。
Is there something which makes this work in a standards-conforming way with only a single memory allocation?
目前,如果没有 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3641.html,这将非常困难,这将允许这样的事情:
struct obj {
char headerCode;
short* data;
};
shared_ptr<obj> make(unsigned len) {
auto p = make_shared<char[]>(sizeof(obj) + sizeof(short)*len));
short* s = static_cast<short*>(p.get() + sizeof(obj));
return shared_ptr<obj>(p, ::new(p.get()) obj{'x', s});
}
这分配了一个 char
的数组,其中 space 足够 obj
和 short
的数组,然后使用新的放置来构造一个 obj
到那个内存中,并创建另一个 shared_ptr
与拥有 char
数组的那个共享所有权。当拥有内存的最后一个 shared_ptr
删除它的引用时,char
数组将被正确删除,但 obj
对象的析构函数不会是 运行,所以重要的是你不要依赖它的析构函数有任何副作用(理想情况下它会有一个微不足道的析构函数)。
您今天可以使用 allocate_shared
和自定义分配器来完成此操作,该分配器会为 short
的数组分配额外的 space,但由于您不知道如何实现会将控制块和您的对象安排在 space 分配中很难计算出 short
数组的开始位置,分配器需要存储在控制块中。