这在c ++ 11中是否合法?使用最新的英特尔编译器进行编译并且似乎可以正常工作,但我只是觉得这是一个侥幸。
class cbase
{
virtual void call();
};
template<typename T> class functor : public cbase
{
public:
functor(T* obj, void (T::*pfunc)())
: _obj(obj), _pfunc(pfunc) {}
virtual void call()
{
(_obj)(*_pfunc)();
}
private:
T& _obj;
void (T::*_pfunc)();
//edited: this is no good:
//const static int size = sizeof(_obj) + sizeof(_pfunc);
};
class signal
{
public:
template<typename T> void connect(T& obj, void (T::*pfunc)())
{
_ptr = new (space) functor<T>(obj, pfunc);
}
private:
cbase* _ptr;
class _generic_object {};
typename aligned_storage<sizeof(functor<_generic_object>),
alignment_of<functor<_generic_object>>::value>::type space;
//edited: this is no good:
//void* space[(c1<_generic_object>::size / sizeof(void*))];
};
具体来说,我想知道void* space[(c1<_generic_object>::size / sizeof(void*))];
是否真的要为c1的成员对象(_obj和_pfunc)提供正确的大小。 (事实并非如此)。
编辑: 因此,经过一些更多的研究后,似乎以下(更多?)正确:
typename aligned_storage<sizeof(c1<_generic_object>),
alignment_of<c1<_generic_object>>::value>::type space;
然而,在检查生成的程序集时,使用带有此空间的placement new似乎会阻止编译器优化掉对“new”的调用(这似乎是在使用常规'_ptr = new c1;'
时发生的EDIT2:更改了代码,使意图更加清晰。
答案 0 :(得分:3)
const static int size = sizeof(_obj) + sizeof(_pfunc);
将给出成员大小的总和,但这可能与包含这些成员的类的大小不同。编译器可以在成员之间或最后一个成员之后自由插入填充。因此,将成员的大小加在一起近似于该对象可能的最小值,但不一定给出具有这些成员的对象的大小。
实际上,对象的大小不仅取决于其成员的类型,还取决于它们的顺序。例如:
struct A {
int a;
char b;
};
VS
struct B {
char b;
int a;
};
在许多情况下,A
会小于B
。在A
中,a
和b
之间通常没有填充,但在B
中,通常会有一些填充(例如,使用4字节的int, b
和a
之间通常会有3个字节的填充。
因此,您的space
可能没有足够的空间来容纳您尝试在init
创建的对象。
答案 1 :(得分:1)
我觉得你很幸运;杰里的回答指出可能存在填充问题。我认为你有一个非虚拟类(即没有vtable),基本上有两个指针(在引擎盖下)。
除此之外,算术:(c1<_generic_object>::size / sizeof(void*))
存在缺陷,因为如果size
不是sizeof(void *)
的倍数,它将被截断。你需要这样的东西:
((c1<_generic_object>::size + sizeof(void *) - 1) / sizeof(void *))
答案 2 :(得分:1)
这段代码甚至没有填充问题,因为它有一些更直接的问题。
模板类c1
定义为包含引用类型的成员T &_obj
。将sizeof
应用于_obj
范围内的c1
将评估为T
的大小,而不是参考成员本身的大小。无法在C ++中获得引用的物理大小(至少直接)。同时,c1<T>
类型的任何实际对象在物理上都包含对T
的引用,这通常在诸如“引擎盖下”的指针的情况下实现。
由于这个原因,我完全不清楚为什么c1<_generic_object>::size
的值被用来作为c1<T>
类型的实际对象的步调构造所需的内存量度(对于任何{{} 1}})。它没有任何意义。这些尺寸根本不相关。
纯粹的运气,空类T
的大小可能会评估为与参考成员的物理实现的大小相同(或更大)的值。在这种情况下,代码将分配足够的内存量。有人甚至可能会声称_generic_object
平等将“通常”在实践中持有。但这只是一个完全随意的巧合,没有任何有意义的基础。
这甚至看起来像是为了纯粹混淆而故意插入代码中的红鲱鱼。
P.S。在GCC sizeof(_generic_object) == sizeof(void *)
中,空类实际上评估为sizeof
,而不是任何“对齐”大小。这意味着保证上述技术使用太小的值初始化1
。更具体地说,在32位GCC中,c1<_generic_object>::size
的值将为c1<_generic_object>::size
,而任何9
的实际大小将为c1<some_type_t>
个字节。