极简 网站模板,网络营销师培训,成都网站建设兴田德润实力强,文创产品推广方案这是一篇对什么是C的The Rule of Three的错误更正和详细说明。阅读时间7分钟。难度⭐⭐⭐虽然上一篇文章的阅读量只有凄惨的两位数#xff0c;但是怀着对小伙伴负责的目的#xff0c;必须保证代码的正确性。这是大厨做技术自媒体的态度。前文最后一段代码是这样的#xff1a… 这是一篇对什么是C的The Rule of Three的错误更正和详细说明。阅读时间7分钟。难度⭐⭐⭐虽然上一篇文章的阅读量只有凄惨的两位数但是怀着对小伙伴负责的目的必须保证代码的正确性。这是大厨做技术自媒体的态度。前文最后一段代码是这样的class Dog { private: char* name; int age; public: ...省略构造和拷贝构造函数... //拷贝赋值函数 Dog operator(const Dog that) { name new char[strlen(that.name)1]; strcpy(name, that.name); age that.age; } ...省略析构函数...};先不谈异常安全这段拷贝赋值函数的代码本身有什么问题有3个问题没有释放原对象指针成员指向的内容没有返回值没有自赋值检查下面我们一个一个分析。 1 没有释放原对象指针这个问题很严重因为一定会造成内存泄露。原因是指针所指的内存未被释放而指针又指向了别处。例子如下我们写了一个main函数长这样int main(int argc, char* argv[]) { Dog D1(Bobby, 2); Dog D2(Teddy, 3); Dog D2 D1;}D1和D2分别是是Dog的对象。根据构造函数的定义D2中的name指针指向了字符数组“Teddy”。而当进行D2 D1操作时name new char[strlen(that.name)1]这一步会在D2中重新创建一个名字为name且指向“Bobby”的指针。这么做也许编译器不会报错但是会有问题。因为在new一个name指针之前原本的name指针指向的内存并没有被释放。而新的name指针只对新创建的内存负责老的内存已经变成无主之地。看来内存泄露是逃不掉了。这个问题看着复杂解决的办法倒是简单只需要在拷贝赋值函数体第一行加上 delete[] name就可以了。class Dog { private: char* name; int age; public: ...省略构造和拷贝构造函数... //拷贝赋值函数 Dog operator(const Dog that) { delete[] name; //释放原对象指针成员指向的内容 name new char[strlen(that.name)1]; strcpy(name, that.name); age that.age; } ...省略析构函数...};2 没有返回值第二个问题犯的错很低级拷贝赋值函数的行为和普通函数一样需要一个返回值。而返回值的类型通常是类的对象的引用。参照常用的写法这里返回*this(this是C类的隐藏成员表示对象本身)。class Dog { private: char* name; int age; public: ...省略构造和拷贝构造函数... //拷贝赋值函数 Dog operator(const Dog that) { delete[] name; //释放原对象指针成员指向的内容 name new char[strlen(that.name)1]; strcpy(name, that.name); age that.age; return *this; //返回对象引用 } ...省略析构函数...};另外大家可能有疑问为什么返回值是一个引用而不是一个值呢答案是只有引用才能进行连续赋值。假设有3个Dog对象D1、D2、D3如果返回值不是引用那么类似D1 D2 D3将不能通过编译。 3 没有自赋值检查什么叫做自赋值就是两个相同对象之间用等号连接比如int main(int argc, char* argv[]) { Dog D1(Bobby, 2); Dog D1 D1; //同一个D1相互赋值}当然一般不会有人写出这样的代码来。这里只是举个简单的例子但是如果在大型项目中不同开发者对同一对象取了不同的别名那么自赋值的情况是有可能发生的。对于上面的Dog类而言如果执行D1 D1那么会发生下面的事情首先对象D1中的name指针被析构name指向的内存被释放然后下一行中的strlen(that.name)又用到了D1的name所指向的内存。重点来了这时你会惊讶地发现编译器提示你name已经不存在了因为在编译器看来你在做对同一对象先释放了内存再使用的非法事情就好比你是拆迁大队的你没有确认拆的是不是自己的房子就不管三七二十一直接拆了然而你晚上还要回家住......C真的烧脑仅仅是不小心把自己赋值给了自己就把自己的一部分给搞丢了这在其他语言中似乎是天方夜谭。但是C似乎很情愿把事情搞复杂。幸好自赋值问题也很容易修复只需要在delete指针之前做一个自赋值的判断。完整代码如下class Dog { private: char* name; int age; public: ...省略构造和拷贝构造函数... //拷贝赋值函数 Dog operator(const Dog that) { if(this ! that) { //判断是否自赋值 delete[] name; //释放原对象的指针指向的内容 name new char[strlen(that.name)1]; strcpy(name, that.name); age that.age; } return *this; } ...省略析构函数...};this ! that这个判断的写法看上去莫名其妙大厨来给大家分析一下this代表D1D1中等号左边的D1that代表等号右边的D1的引用(本质上还是D1)。this和that二者如果相等就说明是同一个对象那么拷贝赋值函数就直接返回对象的引用。至此三个问题终于都解决了 4 总结时刻通过以上问题的剖析可以发现C一大半奇奇怪怪行为的背后都有一个处理不当的指针。另外写一个正确的类真的一点都不简单需要考虑内存泄露返回值类型自赋值等等情况。打住再说下去大厨真的转行成C专业劝退师了。