假设我有以下结构:
template <typename T>
struct Wrapper {
virtual T* get() const = 0;
protected:
void *c_;
};
template <typename C, typename T>
struct WrapperOf: Wrapper<T> {
WrapperOf(C *c = 0) : c_(c) { }
virtual T* get() const {
C *c = static_cast<C*>(c_);
return static_cast<T*>(c->get());
}
};
标准是否保证任何WrapperOf
的大小都相同?通常,我可以执行以下操作:
struct Dummy { void* get(); };
struct Real { int* get(); };
char storage[sizeof(WrapperOf<Dummy, void>)];
Wrapper<int> *wp =
new(storage) WrapperOf<Real, int>();
如果我专注WrapperOf
,通常会:
template <>
struct WrapperOf<void, void>: Wrapper<void> {
virtual void* get() const { return 0; }
};
使用它来初始化存储(以避免使用Dummy
类):
char storage[sizeof(WrapperOf<void, void>)];
这仍然有效吗?
答案 0 :(得分:1)
不,在标准的任何地方都不能保证,因为除了一些狭隘的情况,标准并没有真正对对象大小做出任何保证。
值得注意的是,标准对虚拟功能实现没有任何说明(标准中不存在vptr之类的东西)。
答案 1 :(得分:1)
唯一有大小保证的类型是标准布局类型。多态(以及其他)特别排除了这一点。
但是,你可以做你想要的(我假设你想分配足够的空间来创建任何一种WrapperOf):
#include <memory>
#include <tuple>
struct Dummy { void* get(); };
struct Real { int* get(); };
struct UnReal { float* get(); };
template <typename T>
struct Wrapper {
Wrapper(void* c) : c_(c) {}
virtual T* get() const = 0;
void* get_c() { return c_; }
void* get_c() const { return c_; }
protected:
void *c_;
};
template <typename C, typename T>
struct WrapperOf: Wrapper<T> {
WrapperOf(C *c = 0) : Wrapper<T>(c) { }
virtual T* get() const {
C *c = static_cast<C*>(this->get_c());
return static_cast<T*>(c->get());
}
};
template <>
struct WrapperOf<void, void>: Wrapper<void> {
virtual void* get() const { return 0; }
};
template<class Type, class...Rest>
struct largest_of
{
static constexpr auto x = sizeof(Type);
static constexpr auto y = largest_of<Rest...>::size;
static constexpr std::size_t size = x > y ? x : y;
static constexpr auto q = alignof(Type);
static constexpr auto p = largest_of<Rest...>::alignment;
static constexpr std::size_t alignment = q > p ? q : p;
};
template<class T> struct largest_of<T>
{
static constexpr std::size_t size = sizeof(T);
static constexpr std::size_t alignment = alignof(T);
};
template<class...Ts> struct largest_of<std::tuple<Ts...>> {
static constexpr std::size_t size = largest_of<Ts...>::size;
static constexpr std::size_t alignment =largest_of<Ts...>::alignment;
};
using candidates = std::tuple<
WrapperOf<Real, int>,
WrapperOf<UnReal, float>,
WrapperOf<Dummy, void>,
WrapperOf<void, void>
>;
using largest = largest_of<candidates>;
std::aligned_storage<largest::size, largest::alignment> storage;
int main()
{
auto p1 = new (std::addressof(storage)) WrapperOf<Real,int>();
p1->~WrapperOf<Real,int>();
auto p2 = new (std::addressof(storage)) WrapperOf<UnReal, float>();
p2->~WrapperOf<UnReal,float>();
}
答案 2 :(得分:1)
从当前的工作草案N4640(2017-02-06)
5.3.3 Sizeof [expr.sizeof]
sizeof运算符产生其操作数的对象表示中的字节数。
- 醇>
......申请时 对于一个类,结果是该类对象中的字节数,包括在数组中放置该类型对象所需的任何填充。
所以没有任何保证,只需要花费很多字节就可以了。
即使对于大多数基本类型,标准也表示它是实现定义的
- ... sizeof(char),sizeof(signed char)和sizeof(unsigned char)是1.应用于任何其他基本类型(3.9.1)的sizeof的结果是实现定义的。
醇>
可以推断出某个类需要N个字节,并且根据经验可以看出它对于给定实现中的一系列派生类是相同的。没有保证。