首页 > 其他分享 >第六章 执行期语意学

第六章 执行期语意学

时间:2022-12-13 21:56:37浏览次数:38  
标签:Point 语意 vec 执行期 第六章 new Point3d void delete

第六章 执行期语意学

class Y {
public:
  Y();
  ~Y();
  bool operator==(const Y&) const;
};

class X{
public:
  X();
  ~X();
  operator Y() const;
  X getValue();
};

执行代码if (yy == xx.getValue()) 会被编译器扩充为:

if (yy.operator==(xx.getValue().operator Y()))

其中还有各种临时变量的定义和析构:

{
    X temp1 = xx.getValue();
  	Y temp2 = temp1.operator Y();
    int temp3 = yy.operator==(temp2);
    if (temp3) ...
    temp2.Y::~Y();
    temp1.X::~X();
}

对象数组

Point knots[10] 对于一个对象数组,编译器会生成一个vec_new 函数和一个vec_delete 函数来负责对象的构造和析构。

void* 
vec_new(
	void *array;	//数组的起始地址
    size_t elem_size;	//每一个class object的大小
    int elem_count;		//数组中的元素个数
    void (*constructor)(void*),
    void (*destructor)(void*)
);
Point knots[10];
vec_new(&knots, sizeof(Point), 10, &Point::Point, 0);
void*
vec_delete(
	void *array;
    size_t elem_size;
    int elem_count;
    void (*destructor)(void*, char);
)

如果是Point knots[10] = {Point(), Point(1.0, 1.0, 0.5), -1.0}, 这种编译器会先对前三个元素进行直接初始化操作,对于后面7个元素调用vec_new 函数。

newdelete 运算符

使用new 运算符给对象分配空间:

Point3d *origin = new Point3d;
//转化为
Point3d* origin;
if (origin = _new(sizeof(Point3d)))
    origin = Point3d::Point3d(origin);
//带有异常处理
if (origin = _new(sizeof(Point3d))) {
    try {
        origin = Point3d::Point3d(origin);
    }
    catch(...) {
        _delete(origin);
        throw;
    }
}

new 运算符的底层实现:

extern void* operator new(size_t size) {
    if (size == 0) size = 1;
    void *last_alloc;
    while(!(last_alloc = malloc(size))) {
        if (_new_handler)
            (*_new_handler)();
        else return 0;
    }
    return last_alloc;
}

因为编译器会自动分配1大小的空间,所以new T[10] 是合法的。

针对数组的new 语意

如果一个对象没有定义默认构造函数和析构函数,针对数组的new调用的还是_new 运算符,而不是vec_new

int *p_array = new int[5];
//会被转化为
int *p_array = (int*)_new(5 * sizeof(int));
struct simple_arr { float f1, f2;}
simple_arr *p_aggr = new simple_aggr[5];

如果一个类含有默认构造函数和析构函数,执行的是vec_new

Point3d *p_array = new Point3d[10];
//被合成为
Point3d *p_array;
p_array = vec_new(0, sizeof(Point3d), 10, &Point3d::Point3d, &Point3d::~Point3d);

当我们析构一个对象数组的时候使用delete[] 运算符,采用delete[10] 在里面注明数字也是可以的,但是目前都不会显式的指定。如果对一个对象数组调用delete ,只会析构数组中的第一个元素。那么delete[] 又是如何知道元素个数的,vec_new 会在分配的内存块中配置一个额外的word 用来记录元素个数。

class Point {
public:
  Point();
  virtual ~Point();
};

class Point3d : public Point {
public:
  Point3d();
  virtual ~Point3d();
};

int main(int argc, char const *argv[])
{
  Point *ptr = new Point3d[10];
  delete [] ptr;
  return 0;
}

基类指针指向来分配子类对象的数组,最后再析构会发生如下的错误:

/usr/bin/ld: /tmp/ccDybcp6.o: in function main': case1.cpp:(.text+0x42): undefined reference to Point3d::Point3d()'
collect2: error: ld returned 1 exit status

当执行析构的时候,通过vec_delete进行析构,我们传过去的是Point 的析构函数,去析构Point3d的对象,大小都不一样,无法析构。

避免上述情况的出现最好的办法就是避免基类指针指向一个派生类对象组成的数组。如果非要这样写,只能通过显式的方式进行析构。

for (int ix = 0; ix < elem_count; ++ ix) {
    Point3d *p = &((Point3d*)ptr)[ix];
    delete p;
}

Placement Operator new的语意

重载的new 运算符,调用方式

Point2w *ptw = new (arena) Point2w;

其中arena指向内存中的一个区块,用来方式新产生的Point2w object , 具体的实现如下:

void* operator new (size_t, void* p) { return p; }

编译器再运行的时候会将其扩充为:

Point2w *ptw = (Point2w*)arena;
if (ptw != 0) ptw->Point2w::Point2w();

如果我们相对arena这块区域在进行重新利用不能直接使用delete 因为这样会将对象的内存区域也释放掉。

delete p2w;	//error, 内存区域被释放掉
p2w = new (arena) Point2w;

为了防止内存区域被释放掉,直接显式的调用析构函数:

p2w->~Point2w;
p2w = new (arena) Point2w;

标签:Point,语意,vec,执行期,第六章,new,Point3d,void,delete
From: https://www.cnblogs.com/gxsoar/p/16980745.html

相关文章

  • 第五章 构造、析构、拷贝语意学
    第五章构造、析构、拷贝语意学纯虚函数的存在在虚基类的时候一定要将析构函数声明为虚函数。编译器在调用派生类析构函数会采用静态调用的方式一层一层的调用每一个虚基......
  • 第六章 系统管理
    第六章系统管理6.1Linux中的进程和服务计算机中,一个正在执行的程序或命令,被叫做“进程”(process)。启动之后一只存在、常驻内存的进程,一般被称作“服务”(service)。......
  • C++课本的练习题及答案(第六章)
    第六章练习题一、选择题1.下列类的定义中正确的是(   )。(A)classa{intx=0;inty=1;}          (B)classb{intx=0;inty=1;};(C)classc{intx;inty;}     ......
  • 第六章实战
    defact(actor):#定义函数print(actor+"开始参演这个剧本")A=input("导演选定的角色是:")act(A)#调用函数  deftaocan(a,b,c,d,e,f):......
  • 第六章实例与实战
    实例01:输出每日一帖(共享版) 在IDLE中创建一个名称为function_tips.py的文件,然后在该文件中创建一个名称为function_tips的函数,在该函数中,从励志文字列表中获取一......
  • 第六章:bootstrap基础
    bootstrap简介该框架已经帮你写好了很多的页面样式,你如果需要使用,只需要下载对应的文件,之后直接cv拷贝即可在使用bootstrap的时候所有的页面样式都只需要通过class来调节......
  • 第六章练习题
    16、软件验收测试的合格通过准则是(ABCD)。你的答案A软件需求分析说明书中定义的所有功能已全部实现,性能指标全部达到要求。√正确B所有测试项没有残余一级、二级和三级......
  • GXT之旅:第六章:Templates(2)——XTemplate(1)
    XTemplateXTemplate比Template更为有用,除了拥有Template相同的功能之外,还具有更多有用的功能——提供使用更多的<tpl>标记来满足自己需要的html显示效果。为了下面例子的引......
  • GXT之旅:第六章:Templates(1)——Template(1)
    第六章:Templates本章我们要了解Templates,以及学习他们是如何方便我们去自定义数据的格式化和显示。我们也会详细了解XTemplates的丰富功能本章,我们会涉及到如下GXt功能集Tem......
  • 线上服务异常的定位、处理与优化的探索 - 第六章 监控与自动运维平台
    监控与自动运维平台 Zabbix简介 Zabbix是一个开源的监控平台,基于C/S方式采集数据,并使用B/S的Web方式展示数据。具有主机性能、数据库性能、Web应用、CPU、IO状态、硬......