条款5和条款16

条款5:了解c++默默编写并调用哪些函数
当我们写一个空类时,编译器会自动帮我们生成默认构造函数、析构函数、拷贝构造、以及赋值运算符。
因此对于这个类:

class Demo {};

编译器会生成:

class Demo {
public:
	Demo() {...}
	Demo(const Demo& demo) {...}
	~Demo() {...}

	Demo& operator=(const Demo& demo) {...}
};

知识点:空类的大小为什么为1?
sizeof(Demo) == 1
试想如果类的大小为0,那么在类实例化多个对象时,在地址上就没办法区分类的实例化,所以,为了让每个实例化都有一个唯一的地址,编译器往往会给空类默认加一个字节,这样空类实例化后就得到了唯一的地址,所以空类所占大小为1个字节。

对于下面这个例子:

class Demo {
public:
	void setStr(string str) {
		this->str = str;
	}
	string getStr() {
		return this->str;
	}
	void setNumber(int iNumber) {
		this->iNumber = iNumber;
	}
	int getNumber() {
		return this->iNumber;
	}
private:
	string str;
	int iNumber;
};

int main()
{
	Demo demoA;
	demoA.setStr("hello");
	demoA.setNumber(123);
	Demo demoB(demoA);
	std::cout << demoB.getStr() << std::endl;
	std::cout << demoB.getNumber() << std::endl;
	return 0;
}

我们并没有写Demo类的拷贝构造,但同样得到了正确的输出,这正是编译器的功劳:

hello
123

值得注意的是,Demo的成员变量中有一个string类型的变量,在拷贝时会调用string类的拷贝构造函数完成拷贝。
而int类型的iNumber则是按每一bits完成拷贝。

string类包含默认拷贝构造函数,那如果成员变量包含一个不可拷贝的对象时,又会发生什么呢?

class UnCopyClass {
public:
	UnCopyClass() {}
private:
	UnCopyClass(const UnCopyClass&);
};

class Demo {
public:
	Demo() {}
private:
	UnCopyClass uncopyclass;
};

int main()
{
	Demo demoA;
	Demo demoB(demoA);
	return 0;
}

编译出错:

error C2280: “Demo::Demo(const Demo &)”: 尝试引用已删除的函数

因为Demo类中包含一个不可拷贝的成员变量,默认的拷贝构造函数不知道该怎么办了,这时就需要我们自己实现拷贝构造,即使拷贝时什么也不干(即使想拷贝uncopyclass也拷贝不了)

class Demo {
public:
	Demo() {}
	Demo(const Demo&) {

	}
private:
	UnCopyClass uncopyclass;
};

这样的话编译就不会报错了,只是这个拷贝什么都没干。

条款16:成对使用new和delete时要采取相同形式
首先来说new和delete应该配对使用,而条款中所说的采取相同形式又是什么意思呢?
来看一个例子:

class Demo {
public:
	Demo() {
		cout << "defalut constructor" << endl;
	}
	~Demo() {
		cout << "destructor" << endl;
	}
};

int main()
{
	Demo *demo = new Demo();
	delete demo;
	return 0;
}

程序输出:

defalut constructor
destructor

没有问题,但是对于下面这个程序输出呢?

int main()
{
	Demo *demo = new Demo[5];
	delete demo;
	return 0;
}

程序输出:

defalut constructor
defalut constructor
defalut constructor
defalut constructor
defalut constructor
destructor

可以发现只调用了一次析构函数,并且我的电脑还弹出了:
在这里插入图片描述
但是当我们使用

int main()
{
	Demo *demo = new Demo[5];
	delete[] demo;
	return 0;
}

程序不仅得到了正确的输出,而且没有报错

defalut constructor
defalut constructor
defalut constructor
defalut constructor
defalut constructor
destructor
destructor
destructor
destructor
destructor

分析一下,我们new的是一个Demo类型的数组,因此在delete时也需要表明,需要delete的是一个数组,这样才会依次调用数组中每个对象的析构函数,得到正确的结果。
那如果我们对单个对象执行delete[]呢?

int main()
{
	Demo *demo = new Demo();
	delete[] demo;
	return 0;
}

运行程序发现,程序不断的输出destructor
正如书中所说delete会读取若干内存并把它解释为“数组大小”,结局让人不太愉快。

因此如果在new时使用了[],那么必须在相应的delete中也使用[],反之亦然

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高二的笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值