我制作了几个宏,以便更轻松地使用贴片新内容。我只是想知道是否有任何明显的情况,这些都不会起作用。感谢。
#define CONSTRUCT_INPLACE(TYPE,STORAGE,INIT) ::new((TYPE*)STORAGE) TYPE INIT
#define DESTRUCT_INPLACE(TYPE,STORAGE) ((TYPE*)STORAGE)->~TYPE()
答案 0 :(得分:6)
我不是新位置的专家,但是你如何定义宏有几个问题。
最明显的问题是使用强制转换(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();
我写了一篇博文,回顾了如何使用这种类型的重载决策来实现自定义分配器。
宏中的表达式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 *)'类型是无害的,但是没用。