条款5和条款16

简介: 条款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中也使用[],反之亦然

相关文章
|
6月前
|
缓存 编译器 C++
条款23和条款24
条款23和条款24
|
6月前
|
安全
AIGC知识产权赔偿条款
【2月更文挑战第9天】AIGC知识产权赔偿条款
58 3
AIGC知识产权赔偿条款
|
6月前
|
C++
条款10和条款13
条款10和条款13
|
6月前
|
编译器 C语言 C++
条款20和条款21
条款20和条款21
|
6月前
|
编译器 C++
条款6和条款7
条款6和条款7
|
6月前
条款9和条款22
条款9和条款22
|
Cloud Native 架构师 数据管理
【企业架构】新的企业架构条款和证书出现
【企业架构】新的企业架构条款和证书出现
|
BI 小程序
纯干货:四招帮您捍卫商标权利
纯干货:四招帮您捍卫商标权利
241 0
纯干货:四招帮您捍卫商标权利
|
存储 安全 JavaScript
延期公告:OV代码签名证书私钥保护新规,延期至明年6月执行
今年6月发布的OV代码签名证书私钥保护新规,原定于2022 年11月15日开始执行,现确定将延期至2023年6月1日执行。
123 0
延期公告:OV代码签名证书私钥保护新规,延期至明年6月执行