当前位置: 首页> 房产> 建材 > 自助建站系统哪个最好用_创建网站能赚钱吗_深圳头条新闻_网推公司干什么的

自助建站系统哪个最好用_创建网站能赚钱吗_深圳头条新闻_网推公司干什么的

时间:2025/8/6 15:39:17来源:https://blog.csdn.net/2401_85828611/article/details/146240892 浏览次数:2次
自助建站系统哪个最好用_创建网站能赚钱吗_深圳头条新闻_网推公司干什么的

目录

1.未显示定义的拷贝构造函数

1.内置类型完成浅拷贝或值拷贝

代码示例

汇编代码分析

2.自定义类型会调用它的拷贝构造

3.某些情况下不写拷贝构造函数会出现问题

分析

提问:st1和st2谁先析构?

方法1:从栈帧空间分析

方法2:查看反汇编代码

解决方法

4.讨论函数的返回类型:自定义类型或自定义类型的引用

分析

删去function1、function2和function4,只保留function3,单步执行查看问题

步骤分析


承接CD14.【C++ Dev】类和对象(5)文章

1.未显示定义的拷贝构造函数

之前在CD14.【C++ Dev】类和对象(5)文章中提到过拷贝构造函数的第三个特点:若未显式定义,编译器会生成默认的拷贝构造函数,默认的拷贝构造函数对象按字节序完成拷贝,即浅拷贝或值拷贝

1.内置类型完成浅拷贝或值拷贝

代码示例

#include <iostream>
using namespace std;
class Date 
{
public:Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}private:int _year; int _month; int _day;
};int main()
{Date d1(2025,3,13);Date d2(d1);return 0;
}

下断点至return 0;查看d2的成员变量的值:

成功拷贝构造

汇编代码分析

过程调用图:

发现拷贝构造函数Date d2(d1)直接被展开了,没有使用call指令,使用三个不同的寄存器eax、ecx和edx来拷贝构造d2的三个成员变量

2.自定义类型会调用它的拷贝构造

例如用两个栈实现一个队列,例如:

class MyQueue
{
public:MyStack pushst;MyStack popst;
};

MyQueue不需要写它的拷贝构造,直接调用自定义类型MyStack的拷贝构造

3.某些情况下不写拷贝构造函数会出现问题

例如栈,若不写默认拷贝构造函数:

改造CD13的文章的代码

#include <stdlib.h>
typedef int STDataType;
class MyStack
{
public:MyStack(int init_capacity=4){a = (STDataType*)malloc(sizeof(STDataType) * init_capacity);if (a == nullptr){perror("malloc fail");return;}capacity = init_capacity;top = 0;}~MyStack(){free(a);a = nullptr;}STDataType* a;int top;int capacity;
};

测试以下代码:


int main()
{MyStack st1;MyStack st2(st1);return 0;
}

运行结果出错

分析

MyStack类没有写拷贝构造函数,而是编译器自动生成的拷贝构造函数,因此执行MyStack st2(st1);时为浅拷贝或值拷贝,按字节拷贝

则st1和st2的指针a都是同一个值,可以在return 0处下断点验证:

st1.a和st2.a都指向同一块由malloc动态分配的内存空间,画图则为:

则在出类域时, st1和st2都要调用析构函数,则导致同一块动态分配的内存空间被析构两次!

提问:st1和st2谁先析构?

方法1:从栈帧空间分析

栈帧空间的开辟顺序:main函数-->st1-->st2,而析构顺序恰好相反,为st2-->st1

方法2:查看反汇编代码

解决方法

必须手动实现a的拷贝(换句话说,这里为深拷贝),代码如下:

#include <stdlib.h>
#include <cstring>
typedef int STDataType;
class MyStack
{
public:MyStack(int init_capacity=4){a = (STDataType*)malloc(sizeof(STDataType) * init_capacity);if (a == nullptr){perror("malloc fail");return;}capacity = init_capacity;top = 0;}MyStack(const MyStack& st){a = (STDataType*)malloc(sizeof(STDataType) * st.capacity);if (a == nullptr){perror("malloc fail");return;}memcpy(a, st.a,st.top * sizeof(int));capacity = st.capacity;top = st.top;}~MyStack(){free(a);a = nullptr;}STDataType* a;int top;int capacity;
};int main()
{MyStack st1;MyStack st2(st1);return 0;
}

4.讨论函数的返回类型:自定义类型或自定义类型的引用

对比下面4个函数的区别:

MyStack& function1()
{static MyStack st;return st;
}MyStack function2()
{MyStack st;return st;
}MyStack& function3()
{MyStack st;return st;
}MyStack function4()
{static MyStack st;return st;
}

分析

function1:注意到内部定义的st是静态的,存储在静态区中,栈帧销毁时,st不会销毁,因此返回MyStack的引用不会出现问题

function2:注意到内部定义的st存储在function2的栈帧空间中,栈帧销毁时,虽然st会销毁,但返回的是MyStack的拷贝,不会出现问题

function3:注意到内部定义的st存储在function3的栈帧空间中,栈帧销毁时,st会销毁,返回的是st的引用,如果使用返回值会造成非法访问(即访问已经销毁的st),因此function3有问题

function4:注意到内部定义的st是静态的,存储在静态区中,栈帧销毁时,st不会销毁,不会有问题,而且返回MyStack的拷贝,更不会出现问题

可以使用以下的测试代码来验证上述的说法:

#include <stdlib.h>
#include <cstring>
typedef int STDataType;
class MyStack
{
public:MyStack(int init_capacity=4){a = (STDataType*)malloc(sizeof(STDataType) * init_capacity);if (a == nullptr){perror("malloc fail");return;}capacity = init_capacity;top = 0;}MyStack(const MyStack& st){a = (STDataType*)malloc(sizeof(STDataType) * st.capacity);if (a == nullptr){perror("malloc fail");return;}memcpy(a, st.a,st.top * sizeof(int));capacity = st.capacity;top = st.top;}~MyStack(){free(a);a = nullptr;}STDataType* a;int top;int capacity;
};
MyStack& function1()
{static MyStack st;return st;
}MyStack function2()
{MyStack st;return st;
}MyStack& function3()
{MyStack st;return st;
}MyStack function4()
{static MyStack st;return st;
}int main()
{MyStack ret1 = function1();MyStack ret2 = function2();MyStack ret3 = function3();MyStack ret4 = function4();return 0;
}

直接运行会报错:

在ret3处下断点,调试后查看ret1和ret2,没有问题

删去function1、function2和function4,只保留function3,单步执行查看问题

演示视频参见(链接:https://live.csdn.net/v/469330)

CD15文章的function3的演示视频

步骤分析

1.执行到MyStack ret3 = function3();时,先调用function3函数

2.进入function3函数中,来到了MyStack st;句,会调用它的构造函数MyStack(int init_capacity=4)

,可以访问a指向的空间

3.由于st是局部对象,因此return st前,需要调用析构函数,释放动态分配的内存空间,并将a置为

4.返回st的引用后,调用拷贝构造函数来拷贝构造ret3,在memcpy(a, st.a,st.top * sizeof(int));中虽然a不为空,但st.a为空(之前free掉内存后被手动置空了)

空指针是不能被访问的,因此报错

就算不置空,访问也会出现错误,因为是野指针,比如下图:

*除此之外,function2比function3更消耗时间,因为function2是传值返回,需要拷贝数据

结论

不能返回局部对象的引用!

关键字:自助建站系统哪个最好用_创建网站能赚钱吗_深圳头条新闻_网推公司干什么的

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: