【发布时间】:2020-01-21 10:18:35
【问题描述】:
在我想避免动态内存分配的情况下,我将 new 运算符替换为本质上使用某些静态分配对象的内存的进程(下面的 Storage 类)。您可以在下面看到一个最小的工作示例:
#include <cassert>
#include <iostream>
struct Object {
Object() { std::cout << "Creating a new object\n"; }
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
我的问题与对构造函数的调用次数有关。当我run 上述程序时,我希望调用构造函数两次(在上面的 cmets 中标记为 1 和 2)但我得到的输出是:
创建一个新对象
创建一个新对象
创建一个新对象
为什么构造函数被调用三次?我只希望通过静态对象和对放置 new 的调用来调用构造函数。我尝试使用 gdb 跟踪代码,但这对我来说毫无意义,因为位置 //3 是 where 对构造函数的第三次调用。
我想知道的原因是因为出现了一个案例,这个额外的构造函数调用会导致不必要的副作用;到现在为止,这个额外的调用没有被注意到。
【问题讨论】:
-
@Jarod42 编号的 cmets 是断点告诉我调用的来源。一个来自静态初始化,一个在placement new;问题是:第三个是什么?
-
@Someprogrammerdude 这是
#0 Object::Object (this=0x555555756160 <Storage>) at placement.cpp:7 #1 0x0000555555554a4f in main () at placement.cpp:31(第7行是cout,第31行是main中的单行) -
不应该placement new 运算符 not(!) 为对象调用placement new 吗?所以第一个是
Storage::where,第二个是operator new,第三个是main-function。 -
对
operator new函数应该做什么是一个误解:它应该只分配内存,而不是构造对象。因此它不应该做placement-new。 -
附带说明(因为您的问题已经得到解答),您不需要静态分配对象,将其替换为“char buf[sizeof(Object)];”并且构造函数只被调用一次。
标签: c++ placement-new