C++构造与析构
C++语言构造函数与析构函数需要注意的地方。
构造
考虑以下定义
struct Node
{
char *name;
int value;
Node(char *name = "", int value = )
{
name = new char[strlen(name)+];
strcpy(name, name);
value = value;
}
}
声明两个对象
Node node1("child", ), node2(node1);
这行语句创建了两个对象node1,node2,其中node2是用node1的成员进行初始化,现在改变node2成员值
strcpy(node2.name, "parent");
node2.value = ;
打印对象的成员值如下
cout<<node1.name<<' '<<node1.value<<' '<<node2.name<<' '<<node2.value;
结果如下
parent parent
问题出在Node结构成员name是一个指针类型,如果结构定义中没有复制构造函数,则编译器使用默认的构造函数,此构造函数在复制值类型与复制指针类型时实现方法不同,复制指针类型时仅仅复制指针的内容(所指向的地址),所以node1和node2的name指针指向了同一个地址。
解决这个问题的办法是自定义一个复制构造函数
struct Node
{
char *name;
int value;
Node(char *name = "", int value = )
{
name = new char[strlen(name)+];
strcpy(name, name);
value = value;
}
Node(const Node& node)
{
name = new char[strlen(node.name) + ];
strcpy(name, node.name);
value = node.value;
}
当然,还有一个类似的问题就是
node2 = node1;
这句代码也是对成员进行浅表复制,解决的办法就是自定义赋值构造函数,仅给出代码片段
Node& operator=(const Node& node)
{
if(this != &n) { // no assignment to itself
if(name != )
delete [] name; // 注意这里是 delete [],delete只是析构单个对象,而非字符数组
name = new char[strlen(node.name) + ];
strcpy(name, node.name);
value = node.value;
}
return *this;
}
析构
对于以上类型的对象,因为是值类型,所以如果是作为局部变量,当对象处于作用范围之外时将被销毁,被对象占用的内存也会得到释放。然而,这个对象占用的内存虽然被释放,但是跟这个对象相关联的内存则不一定被释放。如上面这个Node类型,有一个指向string的指针成员,因此,销毁Node类型对象时,对象的指针成员(name)所占用的内存被释放(32位机器上指针占用4byte),但是指针指向的string所占用的内存将会变得无法访问,这个内存也就无法被释放了。为了避免这个问题,类(结构)定义中需要包含析构函数。析构函数在对象被销毁时自动被调用,或者主动使用delete关键字调用析构函数。析构函数不接受参数,也不返回值。
在Node的定义增加一个析构函数
~Node()
{
if(name != )
delete [] name;
}
以上讨论了结构(struct)的构造函数和析构函数,对于类(class)的情况类似。
C++构造与析构的更多相关文章
- C++浅析——继承类中构造和析构顺序
先看测试代码,CTEST 继承自CBase,并包含一个CMember成员对象: static int nIndex = 1; class CMember { public: CMember() { p ...
- Effective C++ -----条款09:绝不在构造和析构过程中调用virtual函数
在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层).
- 【09】绝不在构造和析构过程中调用virtual方法
1.绝不在构造和析构过程中调用virtual方法,为啥? 原因很简单,对于前者,这种情况下,子类专有成分还没有构造,对于后者,子类专有成分已经销毁,因此调用的并不是子类重写的方法,这不是程序员所期望的 ...
- C++不能中断构造函数来拒绝产生对象(在构造和析构中抛出异常)
这是我的感觉,具体需要研究一下- 找到一篇文章:在构造和析构中抛出异常 测试验证在类构造和析构中抛出异常, 是否会调用该类析构. 如果在一个类成员函数中抛异常, 可以进入该类的析构函数. /// @f ...
- STL——空间配置器(构造和析构基本工具)
以STL的运用角度而言,空间配置器是最不需要介绍的东西,它总是隐藏在一切组件(更具体地说是指容器,container)的背后,默默工作,默默付出.但若以STL的实现角度而言,第一个需要介绍的就是空间配 ...
- 魔法方法:构造和析构 - 零基础入门学习Python041
魔法方法:构造和析构 让编程改变世界 Change the world by program 构造和析构 什么是魔法方法呢?我们来系统总结下: - 魔法方法总是被双下划线包围,例如__init__ - ...
- 再探Delphi2010 Class的构造和析构顺序
发了上一篇博客.盒子上有朋友认为Class的构造和析构延迟加载.是在Unit的初始化后调用的Class的构造.在Unit的反初始化前调用的Class的析构函数. 为了证明一下我又做了个试验 unit ...
- Effective C++_笔记_条款09_绝不在构造和析构过程中调用virtual函数
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为方便采用书上的例子,先提出问题,在说解决方案. 1 问题 1: ...
- STL—对象的构造与析构
STL内存空间的配置/释放与对象内容的构造/析构,是分开进行的. 对象的构造.析构 对象的构造由construct函数完成,该函数内部调用定位new运算符,在指定的内存位置构造对象 ...
- C++反汇编第二讲,不同作用域下的构造和析构的识别
C++反汇编第二讲,不同作用域下的构造和析构的识别 目录大纲: 1.全局(静态)对象的识别,(全局静态全局一样的,都是编译期间检查,所以当做全局对象看即可.) 1.1 探究本质,理解构造和析构的生成, ...
随机推荐
- java学习笔记:反射
1.什么是反射? Reflection(反射)是被视为动态语言的关键,反射机制允许程序做执行期间借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象内部属性及方法 2.反射相关的 ...
- js格式化时间为JSON格式 ajax提交 后台处理
var effectRow = new Object();if ($('#grd_infos').datagrid('getChanges').length) { var update = $( ...
- git submodule相关操作
$ cd 项目目录 // 初始化 $ git init $ git submodule add https://github.com/XXXX // 普通更新 $ git submodule upda ...
- 鼠标形状css样式
鼠标形状css样式 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- java error:编码gbk的不可映射字符
解决方法: javac -encoding UTF-8 XX.java
- POJ 2484 A Funny Game
博弈. $n>=3$,后手赢,否则先手赢. #pragma comment(linker, "/STACK:1024000000,1024000000") #include& ...
- C#基础、基础知识点(新人自我总结,开启java学习之路)
从2016年12月29开班,开课到现在C#基础已经算是简答的学习了一点,一个为期两周的课程,或多或少对现在学的Java有着一定的帮助吧,我们先从软件入门来接触c#这门语言: 一.软件开发中的常用术语: ...
- CSS样式类型
CSS样式可以写在哪些地方呢?从CSS 样式代码插入的形式来看基本可以分为以下3种:内联式.嵌入式和外部式三种.这一小节先来讲解内联式 (一)内联式样式 内联式css样式表就是把css代码直接写在现有 ...
- Asp.net简单代码设置GridView自适应列宽不变形
动态绑定的GridView由于列数不固定,而列又太多,是要自定设置gridView的宽度 //在GridView的行数据绑定完的事件中设置 protected void gvObjectList_Ro ...
- c#如何使两个方法并行运行
static void Main(string[] args) { Parallel.Invoke(Foo, Bar); } static void ...