这些放置新宏是否正确?

时间:2009-10-16 23:57:06

标签: c++ macros placement-new

我制作了几个宏,以便更轻松地使用贴片新内容。我只是想知道是否有任何明显的情况,这些都不会起作用。感谢。

#define CONSTRUCT_INPLACE(TYPE,STORAGE,INIT)   ::new((TYPE*)STORAGE) TYPE INIT
#define DESTRUCT_INPLACE(TYPE,STORAGE)         ((TYPE*)STORAGE)->~TYPE()

5 个答案:

答案 0 :(得分:6)

我不是新位置的专家,但是你如何定义宏有几个问题。

第1期

最明显的问题是使用强制转换(TYPE*)STORAGE作为存储位置。这是不正确的。 Placement new只是另一个C ++函数,它参与重载解析等操作。任意地将内存转换为特定类型可能会导致placement new绑定到用户期望的另一个new运算符。

例如,有以下两个placement new定义是有效的。您的宏可能会导致调用错误的宏。

void * _cdecl operator new(size_t cbSize, void* pv);
void * _cdecl operator new(size_t cbSize, SomeType* pv)-

...

// These two call different overloads
void* p = malloc(sizeof(SomeType));
SomeType* f1 = CONSTRUCT_INPLACE(SomeType, p,()) 
SomeType* f2 = new (p) SomeType();

我写了一篇博文,回顾了如何使用这种类型的重载决策来实现自定义分配器。

第2期

宏中的表达式STORAGE应该包含在parens中以防止恶意宏扩展错误。

::new((TYPE*)(STORAGE)) TYPE INIT

答案 1 :(得分:2)

除了其他地方陈述的问题,您的宏与模板类型的交互非常糟糕(即无法编译)。

通常,当没有明显的好处时,应该避免使用宏。说实话,我在这里看不到真正的好处。

e.g。

template< class A, class B >
class T
{
public:

    T(A y, B z) : x(y), w(z) {}
    A x;
    B w;
};

int main()
{
    void* p = ::operator new(sizeof(T));

    CONSTRUCT_INPLACE(T<int, double>, p, (4, 5.0));

    DESTRUCT_INPLACE(T<int, double>, p);

    ::operator delete(p);

    return 0;
}

答案 2 :(得分:1)

看着他们,我想知道第一次(TYPE*)演员阵容是什么 - 毕竟新位置需要void*

但话又说回来,我想知道它们对它们有什么好处。他们所管理的只是进一步模糊一些开始时并非微不足道的事情。为什么你认为你需要它们?

话虽如此,您是否看过(无可否认的)标准库设施来处理未初始化的内存? (请参阅this网站的下半部分。您可以使用某些内容。

答案 3 :(得分:0)

你的CONSTRUCT_INPLACE对我来说有点奇怪。用法是:

void* p = <some memory location>;
Foo* f = CONSTRUCT_INPLACE(Foo, p, Foo())

// The macro-free version seems easier to read:
Foo* f = new(p) Foo();

DESTRUCT_INPLACE至少比它取代的代码更容易阅读。

但实际上,为什么你这么多的位置做这些宏对你有用?把那些东西放在一个池类中然后忘了它。

答案 4 :(得分:0)

Placement-new运算符在最初是“原始”内存块的位置创建一个对象。即传递给placement new的内存指针的正确类型是'void *'。像它一样将它转换为'(TYPE *)'类型是无害的,但是没用。 顺便说一句,有这些宏的重点是什么?你说他们“使用新的放置更容易”,但他们似乎只是执行一些完全不必要的演员。