我制作了几个宏来使使用placement new 更容易一些。我只是想知道是否有任何明显的情况下这些不起作用。谢谢。
#define CONSTRUCT_INPLACE(TYPE,STORAGE,INIT) ::new((TYPE*)STORAGE) TYPE INIT
#define DESTRUCT_INPLACE(TYPE,STORAGE) ((TYPE*)STORAGE)->~TYPE()
我制作了几个宏来使使用placement new 更容易一些。我只是想知道是否有任何明显的情况下这些不起作用。谢谢。
#define CONSTRUCT_INPLACE(TYPE,STORAGE,INIT) ::new((TYPE*)STORAGE) TYPE INIT
#define DESTRUCT_INPLACE(TYPE,STORAGE) ((TYPE*)STORAGE)->~TYPE()
我不是放置新的专家,但您如何定义宏存在一些问题。
最明显的问题是使用铸件(TYPE*)STORAGE
作为存储位置。这是不正确的。Placement new 只是另一个 C++ 函数,它参与诸如重载决议之类的操作。任意将内存转换为特定类型可能会导致放置 new 绑定到用户期望的不同 operator new。
例如,有以下两个放置 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 应该用括号括起来,以防止邪恶的宏扩展错误。
::new((TYPE*)(STORAGE)) TYPE INIT
除了其他地方提到的问题之外,您的宏与模板类型的交互非常糟糕(即无法编译)。
一般来说,当没有明显的好处时,应该避免使用宏。老实说,我在这里看不到真正的好处。
例如
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;
}
看着他们,我想知道第一个(TYPE*)
演员是为了什么——void*
毕竟新的位置。
但话又说回来,我想知道它们到底有什么用。他们所能做的就是进一步混淆一些一开始并不简单的事情。为什么你认为你需要它们?
话虽这么说,您是否查看过(当然很少)用于处理未初始化内存的标准库工具?(请参阅本网站的下半部分。可能有一些您可以使用的东西。
你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
至少比它替换的代码更容易阅读。
但实际上,您为什么要做这么多新的展示位置以使这些宏对您有用?把这些东西放在泳池课上,然后忘掉它。
Placement-new 运算符在最初的“原始”内存块中创建一个对象。即传递给新位置的内存指针的正确类型是'void*'。正如您所做的那样,将其转换为类型“(TYPE *)”是无害的,但没用。您的“DESTRUCT”宏中的演员表的意义也不是很清楚。
顺便说一句,拥有这些宏有什么意义?您说他们“使使用新位置更容易一些”,但他们似乎所做的只是执行一些完全不必要的演员表。