C++ 基于模板sizeof()的新放置
这在c++11中合法吗?用最新的英特尔编译器编译,看起来可以工作,但我觉得这是一种侥幸C++ 基于模板sizeof()的新放置,c++,templates,c++11,signals,placement-new,C++,Templates,C++11,Signals,Placement New,这在c++11中合法吗?用最新的英特尔编译器编译,看起来可以工作,但我觉得这是一种侥幸 class cbase { virtual void call(); }; template<typename T> class functor : public cbase { public: functor(T* obj, void (T::*pfunc)()) : _obj(obj),
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*))];
};
class-cbase
{
虚空调用();
};
模板类函子:公共cbase
{
公众:
函子(T*obj,void(T::*pfunc)()
:_obj(obj),_pfunc(pfunc){}
虚拟无效调用()
{
(obj)(pfunc)();
}
私人:
T&u obj;
无效(T:*pfunc)();
//编辑:这不好:
//常量静态int size=sizeof(_obj)+sizeof(_pfunc);
};
类信号
{
公众:
模板无效连接(T&obj,无效(T::*pfunc)()
{
_ptr=新(空间)函子(obj,pfunc);
}
私人:
cbase*\u ptr;
类_泛型_对象{};
typename对齐_存储::类型空间;
//编辑:这不好:
//void*空间[(c1::大小/大小(void*))];
};
具体地说,我想知道是否void*space[(c1::size/sizeof(void*))]
将为c1的成员对象(_obj和_pfunc)提供正确的大小。(事实并非如此)
编辑:
因此,经过更多的研究,以下内容似乎(更多?)是正确的:
typename对齐存储::类型空间;
但是,在检查生成的程序集时,在该空间中使用placement new似乎会阻止编译器优化对“new”的调用(这似乎是在仅使用常规的“_ptr=new c1;”时发生的)
EDIT2:更改代码以使意图更清晰。
const static int size=sizeof(_obj)+sizeof(_pfunc);
将给出成员大小的总和,但这可能与包含这些成员的类的大小不同。编译器可以在成员之间或最后一个成员之后自由插入填充。因此,将成员大小相加近似于该对象可能的最小值,但不一定是g我用这些构件测量一个物体的大小
事实上,对象的大小不仅取决于其成员的类型,还取决于其顺序。例如:
struct A {
int a;
char b;
};
vs:
在许多情况下,A
比B
小。在A
中,A
和B
之间通常没有填充,但在B
中,通常会有一些填充(例如,对于4字节的int,在B
和A
之间通常会有3字节的填充)
因此,您的
空间
可能没有足够的…空间来容纳您试图在init
中创建的对象。我认为您很幸运;Jerry的回答指出可能存在填充问题。我认为您拥有的是一个非虚拟类(即,没有vtable),基本上有两个指针(在引擎盖下)
除此之外,算法:(c1::size/sizeof(void*)
是有缺陷的,因为如果size
不是sizeof(void*)
的倍数,它将被截断。您需要类似以下内容:
((c1::size+sizeof(void*)-1)/sizeof(void*))
此代码甚至不涉及填充问题,因为它有一些更直接的问题
<>模板类<代码> C1 < /C> >定义为包含引用类型的成员<代码> t+yObj>代码>应用< <代码> >代码> c1
的实际对象都会在物理上包含对T
的引用,通常在这种情况下作为“引擎盖下”的指针来实现
由于这个原因,我完全不清楚为什么c1::size
的值被用作c1
(对于任何T
)类型的实际对象的速度构造所需的内存的度量。这没有任何意义。这些大小根本不相关
纯粹幸运的是,空类\u generic\u对象的大小可能与引用成员的物理实现的大小计算为相同(或更大)的值。在这种情况下,代码将分配足够的内存量。甚至有人可能会声称sizeof(\u generic\u object)==sizeof(void*)
相等“通常”在实践中是成立的。但这只是一个完全武断的巧合,没有任何有意义的依据
这甚至看起来像是故意为了纯粹的混淆而在代码中插入的红鲱鱼
在GCCsizeof
中,空类的p.S.实际计算结果为1
,而不是任何“对齐”"大小。这意味着上述技术保证使用太小的值初始化c1::size
。更具体地说,在32位GCC中c1::size
的值将是9
,而任何c1
的实际大小将是12
字节。如果不提供在c1
中为引用成员定义一个初始值设定项?该引用成员中是否有任何特定的重要性?另外,通过sizeof(_obj)
计算内存大小的背后的想法是什么,它计算为完整对象的大小(即sizeof T
),然后在该位置构造一个c1
对象,该对象在物理上只包含对某些类型的引用(作为指针实现)?我不知道它是否编译,这是一个非常简单的示例,我在这里发布,以转到相关部分。我正在编写一个信号/回调类,希望尽可能消除动态内存分配。嗯,在这一点上,代码似乎没有任何意义。您可能是偶然的吗
struct A {
int a;
char b;
};
struct B {
char b;
int a;
};