我想说
每天坚持一点点,坚持带来大改变
今天是刷题的第_12天,加油!
一、选择题
这道题存在多个错误
错误一:在析构函数中调用delete this
我们知道,使用delete会有两步:
1. 调用析构函数释放对象中的资源
2. 调用operator delete释放该对象
题目中,在myClass的析构函数中delete this,那么首先就会调用~myClass()
,然后再释放空间。但是调用~myClass()
又会去delete this,每次调用delete this都会去调用~myClass
,而~myClass()
又会去调用delete,互相调用形成死循环,从而导致栈溢出,程序崩溃!
注意:只是在析构函数中delete this是可以通过编译的,但是运行的时候会形成死循环导致程序崩溃
错误二:对this进行更改
题目中,this = NULL这句代码是错误的,因为this的类型是类类型* const this
,所以this是不能被更改的,this指向的内容可以被更改!所以因为this=NULL这句代码,会导致编译失败!
错误三:delete是对new出来的对象进行释放,并不是所有的对象都是从堆上new出来的
题目中,delete this,但是该对象并不一定是在堆上new出来的,对于myClass* ptr = new myClass,我们可以通过delete ptr进行释放。但是这个this所指的对象,可能就是在栈上创建的静态对象:myClass obj,采用delete对栈对象进行释放的话,首先会调用该对象的析构函数(这一步没问题),然后调用operator delete释放对象空间(这一步就会出现非法堆指针错误!)
综上所述,所以最后程序的运行结果是:无法通过编译
总结:
在成员函数中调用delete this,会导致指针错误
在析构函数中调用delete this,会导致堆栈溢出(死循环)
A: 对于一个类,如果我们不显式写构造函数,编译器会自动生成一个无参数的构造函数,但是如果我们自己显式定义了,这个无参数的默认构造函数就不会生成。所以有没有无参数的构造函数取决于我们自己。
B: 误区:并不是每一个类都有一个拷贝构造函数!虽然对于拷贝构造函数,我们不显式定义编译器会自动生成一个拷贝构造函数,但是我们可以人为的让其没有拷贝构造函数。看如下代码:
class A{
public:
A(){};
~A();
A(A&); //声明一个拷贝构造函数,编译器也不会生成了!
}
在main函数中调用其拷贝构造,程序运行结果是:链接错误,无法找到拷贝构造函数!也就是说,编译器看到有用户显式写的拷贝构造的声明之后,便不会生成默认的拷贝构造函数了,我们可以通过声明但不定义拷贝构造,从而让该类没有拷贝构造
补充知识:C++11中有专门的方式可以让一个类没有拷贝构造:
A(A&) = delete; //即在函数声明后面加一个 =delete,告诉编译器不要生成他的默认函数!
此时如果在主函数中调用该类的拷贝构造,就会提示:尝试引用已删除的函数
总结:写一个没有拷贝构造的类:
1.构造函数只给声明不给定义
2.使用C++11的 =delete,不让编译器自动生成默认拷贝构造
C:拷贝构造也是一种构造函数,可以存在重载!所以每个类可以有多个拷贝构造函数!
D:析构函数没有参数,所以无法重载,每个类只能有一个析构函数!
A:堆的大小取决于操作系统给堆分配多少内存,栈的内存一般很小,正确√
B:new/delete是在堆上随机申请内存,所以频繁申请很容易产生内存碎片问题。而栈的是由编译器自动管理,对于使用完的变量会自动进行销毁,所以不存在此问题!
C:堆只能动态分配,×
D:堆只能动态分配,栈可以动态也可以静态 √
详细的请见我这篇文章:👉6堆栈那些事儿~
二、编程题
1.二进制插入
思路1:拿到m的每一位插入到n的对应位置
即对每一位利用 | 运算
class BinInsert {
public:
int binInsert(int n, int m, int j, int i) {
// write code here
//把m插入到n的第j到i位
int index = 0;
for(int k = j;k<=i;++k)
{
//(m>>index)&1拿到m的每一位
// <<k 就是移动到相应的位置
// 然后|= 就是把m的对应位置插入到n的对应位置
n |= ((1 & (m>>index)) << k);
++index;
}
return n;
}
};
思路2:m直接左移j位,整体或运算
class BinInsert {
public:
int binInsert(int n, int m, int j, int i) {
// write code here
return n | (m<<j);
}
};
2. 查找组成一个偶数最接近的两个素数
给一个偶数n,我们要找组成该偶数的最接近的两个素数
我们可以从 n/2 处开始找,left为左半部分,right为右半部分
如果left和right都是素数,那么就输出这两个数
否则,–left,++right
#include<iostream>
#include<cmath>
using namespace std;
//判断是否为素数
bool ispri(int num)
{
for(int i = 2;i<=sqrt(num);++i)
{
if(num%i==0)
{
return false;
}
}
return true;
}
int main()
{
int n;
cin >> n; //偶数
//找到组成n的两个最小素数
//24:12*2 -> 11 13
//18:9*2 -> 8 10 -> 7 11 √
//思路:从中间向左右找
int left = n/2;
int right = n/2;
//有一个不是素数,就继续循环
while(!ispri(left) || !ispri(right))
{
--left;
++right;
}
cout << left <<endl;
cout << right << endl;
return 0;
}