将放置新与存储类一起使用时的额外构造
Extra construction when using placement new with a storage class
在我想避免动态内存分配的情况下,我将 new 运算符替换为一个本质上使用某些静态分配对象的内存的进程(下面的Storage
类(。您可以在下面看到一个最小工作示例:
#include <cassert>
#include <iostream>
struct Object {
Object() { std::cout << "Creating a new objectn"; }
static void *operator new(size_t);
static void operator delete(void *p);
};
static struct {
Object where;
bool allocated = false;
} Storage; // 1
void *Object::operator new(size_t) {
assert(!Storage.allocated);
auto p = ::new (&Storage.where) Object; // 2
Storage.allocated = true;
return p;
}
void Object::operator delete(void *p) {
assert(Storage.allocated);
static_cast<Object *>(p)->~Object();
Storage.allocated = false;
}
int main() { Object *obj = new Object; } // 3
我的问题与对构造函数的调用次数有关。当我运行上述程序时,我希望调用构造函数两次(在上面的注释中标记为 1 和 2(,但我得到的输出是:
创建新对象
创建新对象
创建新对象
为什么构造函数被称为三次?我只期望通过静态对象和对放置 new 的调用进行构造函数调用。我尝试使用 gdb 跟踪代码,但这对我来说毫无意义,因为位置//3
where
对构造函数的第三次调用
。我想知道的原因是因为出现了一种情况,其中这个额外的构造函数调用会导致不必要的副作用;到目前为止,这个额外的调用还没有被注意到。
出于某种奇怪的原因,您的operator new
在应该只分配内存时调用构造函数。这意味着对new
的调用最终会调用Object
的构造函数两次。operator new
中有一个呼叫,main
中有一个呼叫。
你可能想要这个:
void *Object::operator new(size_t) {
assert(!Storage.allocated);
Storage.allocated = true;
return reinterpret_cast<void *> (&Storage.where);
}
想象一下,如果构造函数采用一个整数参数,并且main
中的行如下所示:
Object *obj = new Object(7);
operator new
如何知道如何正确构造对象?那不是你应该这样做的地方!
Object *obj = new Object;
做两件事:
-
通过调用
operator new
来分配内存 -
调用构造函数。
您的operator new
也调用构造函数,因此此语句调用构造函数两次(全局变量初始化调用一次(。
请注意,delete
是相同的。delete obj;
做两件事:
-
调用析构函数。
-
通过调用
operator delete
解除分配内存
您的operator delete
也不应该调用析构函数,因为这样析构函数会被调用两次。
- 将字符串存储在c++中的稳定内存中
- std::原子加载和存储都需要吗
- C++:将控制台输出存储在宏中更好吗
- 如何将enable-if与模板参数和参数包一起使用
- 如何将PERF_AMPLE_READ与mmap一起使用
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 使用QProcess执行命令,并将结果存储在QStringList中
- 如何将C++中的库和头与MinGW一起使用
- 访问存储在向量C++中的结构的多态成员
- 如何从存储在std::映射中的std::集中删除元素
- 存储模板类型以强制转换回派生<T>
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 为什么我不能将 rand() 与数组的大小一起使用?
- 将放置新与存储类一起使用时的额外构造
- 如果与memory_order_acquire一起存储会发生什么
- 是否可以将存储在dword中的十六进制与getasynckeystate一起使用
- 如何加入两个指针以将其串在一起并将其存储在数组或字符中
- 处理需要在c++中一起存储的3个int类型的正确方法
- C++将基类对象和派生类对象存储在一起
- 将shared_ptr与通用注册表或共享对象存储一起使用.或不