5

这在c ++ 11中合法吗?使用最新的 intel 编译器编译并且似乎可以工作,但我只是觉得这是侥幸。

 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;

然而,在检查生成的程序集时,使用带有此空间的放置 new 似乎会阻止编译器优化对“new”的调用(这似乎发生在仅使用常规 '_ptr = new c1;' 时)

EDIT2:更改了代码以使意图更加清晰。

4

3 回答 3

3

const static int size = sizeof(_obj) + sizeof(_pfunc);将给出成员大小的总和,但这可能与包含这些成员的类的大小不同。编译器可以自由地在成员之间或最后一个成员之后插入填充。因此,将成员的大小加在一起近似于该对象可能的最小大小,但不一定给出具有这些成员的对象的大小。

事实上,对象的大小不仅取决于其成员的类型,还取决于它们的顺序。例如:

struct A { 
    int a;
    char b;
};

与:

struct B { 
    char b;
    int a;
};

在很多情况下,A会小于B。在中,和A之间通常没有填充,但在 中,通常会有一些填充(例如,对于 4 字节的 int,和之间通常会有 3 个字节的填充)。abBba

因此,您space可能没有足够的空间来容纳您尝试在init.

于 2013-06-08T05:47:56.340 回答
1

我认为你很幸运;Jerry 的回答指出可能存在填充问题。我认为你拥有的是一个非虚拟类(即没有 vtable),基本上有两个指针(在引擎盖下)。

除此之外,算术:是缺陷的(c1<_generic_object>::size / sizeof(void*)),因为如果size不是. 你需要类似的东西: sizeof(void *)

((c1<_generic_object>::size + sizeof(void *) - 1) / sizeof(void *))

于 2013-06-08T06:07:32.020 回答
1

这段代码甚至没有涉及填充问题,因为它有一些更直接的问题。

模板类c1被定义为包含T &_obj引用类型的成员。在 of 范围内应用sizeofto将评估 的大小,而不是参考成员本身的大小。在 C++ 中无法获取引用的物理大小(至少直接获取)。同时,任何类型的实际对象都将在物理上包含对 的引用,这通常在这种情况下实现为“引擎盖下”的指针。_objc1Tc1<T>T

出于这个原因,我完全不清楚为什么将 的值c1<_generic_object>::size用作实时构造类型的实际对象c1<T>(对于 any T)所需的内存量度。这没有任何意义。这些尺寸根本不相关。

幸运的是,空类的大小_generic_object可能会评估为与引用成员的物理实现的大小相同(或更大)的值。在这种情况下,代码将分配足够的内存。甚至有人可能会声称,sizeof(_generic_object) == sizeof(void *)在实践中,这种平等“通常”会成立。但这只是一个完全武断的巧合,没有任何有意义的基础。

这甚至看起来像是为了纯粹的混淆目的而故意插入代码中的红鲱鱼。

PS 在sizeof空类的 GCC 中,实际上计算为1,而不是任何“对齐”大小。这意味着上述技术可以保证c1<_generic_object>::size使用太小的值进行初始化。更具体地说,在 32 位 GCC 中, 的值c1<_generic_object>::size将是9,而 any 的实际大小c1<some_type_t>将是12字节。

于 2013-06-08T06:56:38.560 回答