c++ new的三种用法 【由基础到进阶 】

1.运算符

1.内置类型使用new

int * ip1 = new int[5]{1,2,3,4,5};

编译器执行的步骤
1.先计算大小,为int类型,有5个则为20个字节
2.从内存中开辟20个字节空间大小
3.把这个空间初始化为1,2,3,4,5
4.把这个空间的地址赋值给ip1
在这里插入图片描述

2.自己设计的类型使用new

using namespace std;
class Complex {
private:
	int  real;
	int image;
public:
	Complex() :real{ 0 }, image{ 0 }{cout << "create default " << this << endl; }
	Complex(int Areal, int Aimage) :real{ Areal }, image{ Aimage } {cout << "create " << this << endl; }
	~Complex() { cout << "destory " << this << endl; }
	void Print() const {
		cout << "const  " << endl;

	}

	void show() {
		cout << "show" << endl;
		Print();
	}

};
int main() {
	Complex* ap = new Complex[5]{ {1,2},{3,4},{4,5} };
	delete[]ap;
}

在这里插入图片描述
此时我们可以看出,在上越界标志下面记录了对象的数量,
而只有 关键字new的这种用法在内存中才会有对象的数量

因此我们可以这样来

计算创建创建对象的数量

int n = * ((int * )ap - 1);

让我们来运行下面的代码验证一下


class Complex {
private:
	int  real;
	int image;
public:
	Complex() :real{ 0 }, image{ 0 }{cout << "create default " << this << endl; }
	Complex(int Areal, int Aimage) :real{ Areal }, image{ Aimage } {cout << "create " << this << endl; }
	~Complex() { cout << "destory " << this << endl; }
	void Print() {
		cout << real << " " << image << endl;
	}
};
int main() {
	Complex* ap = new(nothrow) Complex[]{ {1,2},{2,3} };
	int n = *((int*)ap - 1);
	for (int i = 0; i < n; ++i) {
		ap[i].Print();
	}
	delete[]ap;

}

结果如下
在这里插入图片描述

当我们使用new的时候,new和delete的使用一定要对应

new -->delete
new [] --> delete []

举个例子:
当这样创建一个对象时

int main() {
	Complex* ap = new Complex(1, 2);

	
}

就要这样释放 delete ap
千万不能写成这样 delete [] ap;
这样编译器会把上越界标志当成要析构的对象的数量,会析构cdcdcdcd个对象
代码运行结果如下
在这里插入图片描述
当这样创建一个对象时


int main() {
	Complex* ap = new Complex[5]{ {1,2},{2,3} };
	

}

释放的时候就要写成这样,delete [] ap;
千万不能写成这样delete ap,
这样的话编译器会只以为只析构一个对象,变会从上越界标志那里开始释放,这样就会造成异常
在这里插入图片描述

3.new分配失败之后便会抛出异常, 我们如果不想让它抛出异常的话,在new后面加上(nothrow)就可以了

Complex* ap = new(nothrow) Complex[5]{ {1,2},{2,3} };
	delete []ap;

2.函数的用法

在这里插入图片描述

与new 不同的点

1.需要手动计算字节大小
2.没有办法初始化
3.返回的地址为void * 类型,需要自己手动强转
1.内置类型使用函数方法
在这里插入图片描述

2.自己设计的类型使用函数方法

class Complex {
private:
	int  real;
	int image;
public:
	Complex() :real{ 0 }, image{ 0 }{cout << "create default " << this << endl; }
	Complex(int Areal, int Aimage) :real{ Areal }, image{ Aimage } {cout << "create " << this << endl; }
	~Complex() { cout << "destory " << this << endl; }
	void Print() {
		cout << real << " " << image << endl;
	}
};
int main() {
	Complex* ap = (Complex*) :: operator new(sizeof(Complex) * 5);
	for (int i = 0; i < 5; ++i) {
		new (&ap[i])  Complex(1, 2);
	}
	for (int i = 0; i < 5; ++i) {
		ap[i].Print();
	}
	for (int i = 0; i < 5; ++i) {
		ap[i].~Complex();
	}
	::operator delete (ap);
	ap = nullptr;
	
}

与new一样,它在分配失败时也会抛出异常
就上面的例子,我们不想让它抛出异常的话,则在后面加上 nothrow就可以了
Complex* ap = (Complex*) :: operator new(sizeof(Complex) * 5,nothrow);

3.定位new

1内置类型使用定位new

在这里插入图片描述
我们对开辟的空间重新定位,存储了3个int数据

2.自己设计的类型使用定位new

1.重定位对象

class Complex {
private:
	int  real;
	int image;
public:
	Complex() :real{ 0 }, image{ 0 }{cout << "create default " << this << endl; }
	Complex(int Areal, int Aimage) :real{ Areal }, image{ Aimage } {cout << "create " << this << endl; }
	~Complex() { cout << "destory " << this << endl; }
	void Print() {
		cout << real << "  " << image << endl;
	}
};
int main() {
	Complex * a =new Complex(1, 2);
	a->Print();
	new (a) Complex(2, 3);
	a->Print();

}

运行结果如下

在这里插入图片描述
我们可以看出,这个对象被重新构造了一次。

2.重定位空间

我们要记住一句话“有空间,不一定有对象,有对象,不一定有空间”。

class A {
private:
	int value;
public:
	A() {}
	A(int Avalue) :value{ Avalue } {
		cout << "create " << value << "   " << this << endl;
	}
	~A() {
		cout << "Destory " << value << "   " << this << endl;
	}
	 void Print() {
		cout << "Print " <<hex<< value << endl;

	}


};

int main() {
	A* a = (A*)malloc(sizeof(A));
	if (a == nullptr) {
		return 1;
	}
	a->Print();

	
}

让我们先运行一下观察一下它的结果。
发现打印的值为cdcdcdcd,为什么会这样呐?
在这里插入图片描述

在这里插入图片描述

这个是a->value的地址,因为在堆中开辟的空间,而堆中的空间默认都拿cdcdcdcd填充,而在调用Print函数的时候,编译器把a->value放到这块地址空间,并打印了出来
在这里插入图片描述
但是,我们要清楚,创建一个对象,必须要调用它的构造函数,此时它只是开辟了空间,始终没有创建对象,这样的话, 这个对象没有它的虚表和虚表指针,

在我们给Print函数前面加了virtual之后,它就会报错。
在这里插入图片描述

在这里插入图片描述
而此时,我们可以直接拿重定位new重新构建这个对象,这样就好了。
在这里插入图片描述

  • 18
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值