- 浏览: 144519 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
Jonathan樊:
请LZ不要简单的Copy过来,好吧?起码编辑一下啊~~该加的超 ...
直接拿来用!最火的Android开源项目 -
tao71535:
学习了、
不过为还是觉得看视频做例子、
比较好、、
Intent总结
题目:下面是一个数组类的声明与实现。请分析这个类有什么问题,并针对存在的问题提出几种解决方案。
分析:我们注意在类的内部封装了用来存储数组数据的指针。软件存在的大部分问题通常都可以归结指针的不正确处理。
这个类只提供了一个构造函数,而没有定义构造拷贝函数和重载拷贝运算符函数。当这个类的用户按照下面的方式声明并实例化该类的一个实例
Array A(10);
Array B(A);
或者按照下面的方式把该类的一个实例赋值给另外一个实例
Array A(10);
Array B(10);
B=A;
编译器将调用其自动生成的构造拷贝函数或者拷贝运算符的重载函数。在编译器生成的缺省的构造拷贝函数和拷贝运算符的重载函数,对指针实行的是按位拷贝,仅仅只是拷贝指针的地址,而不会拷贝指针的内容。因此在执行完前面的代码之后,A.data和B.data指向的同一地址。当A或者B中任意一个结束其生命周期调用析构函数时,会删除data。由于他们的data指向的是同一个地方,两个实例的data都被删除了。但另外一个实例并不知道它的data已经被删除了,当企图再次用它的data的时候,程序就会不可避免地崩溃。
由于问题出现的根源是调用了编译器生成的缺省构造拷贝函数和拷贝运算符的重载函数。一个最简单的办法就是禁止使用这两个函数。于是我们可以把这两个函数声明为私有函数,如果类的用户企图调用这两个函数,将不能通过编译。实现的代码如下:
private:
Array(const Array& copy);
const Array& operator = (const Array& copy);
最初的代码存在问题是因为不同实例的data指向的同一地址,删除一个实例的data会把另外一个实例的data也同时删除。因此我们还可以让构造拷贝函数或者拷贝运算符的重载函数拷贝的不只是地址,而是数据。由于我们重新存储了一份数据,这样一个实例删除的时候,对另外一个实例没有影响。这种思路我们称之为深度拷贝。实现的代码如下:
为了防止有多个指针指向的数据被多次删除,我们还可以保存究竟有多少个指针指向该数据。只有当没有任何指针指向该数据的时候才可以被删除。这种思路通常被称之为引用计数技术。在构造函数中,引用计数初始化为1;每当把这个实例赋值给其他实例或者以参数传给其他实例的构造拷贝函数的时候,引用计数加1,因为这意味着又多了一个实例指向它的data;每次需要调用析构函数或者需要把data赋值为其他数据的时候,引用计数要减1,因为这意味着指向它的data的指针少了一个。当引用计数减少到0的时候,data已经没有任何实例指向它了,这个时候就可以安全地删除。实现的代码如下:
template<typename T> class Array { public: Array(unsigned arraySize):data(0), size(arraySize) { if(size > 0) data = new T[size]; } ~Array() { if(data) delete[] data; } void setValue(unsigned index, const T& value) { if(index < size) data[index] = value; } T getValue(unsigned index) const { if(index < size) return data[index]; else return T(); } private: T* data; unsigned size; };
分析:我们注意在类的内部封装了用来存储数组数据的指针。软件存在的大部分问题通常都可以归结指针的不正确处理。
这个类只提供了一个构造函数,而没有定义构造拷贝函数和重载拷贝运算符函数。当这个类的用户按照下面的方式声明并实例化该类的一个实例
Array A(10);
Array B(A);
或者按照下面的方式把该类的一个实例赋值给另外一个实例
Array A(10);
Array B(10);
B=A;
编译器将调用其自动生成的构造拷贝函数或者拷贝运算符的重载函数。在编译器生成的缺省的构造拷贝函数和拷贝运算符的重载函数,对指针实行的是按位拷贝,仅仅只是拷贝指针的地址,而不会拷贝指针的内容。因此在执行完前面的代码之后,A.data和B.data指向的同一地址。当A或者B中任意一个结束其生命周期调用析构函数时,会删除data。由于他们的data指向的是同一个地方,两个实例的data都被删除了。但另外一个实例并不知道它的data已经被删除了,当企图再次用它的data的时候,程序就会不可避免地崩溃。
由于问题出现的根源是调用了编译器生成的缺省构造拷贝函数和拷贝运算符的重载函数。一个最简单的办法就是禁止使用这两个函数。于是我们可以把这两个函数声明为私有函数,如果类的用户企图调用这两个函数,将不能通过编译。实现的代码如下:
private:
Array(const Array& copy);
const Array& operator = (const Array& copy);
最初的代码存在问题是因为不同实例的data指向的同一地址,删除一个实例的data会把另外一个实例的data也同时删除。因此我们还可以让构造拷贝函数或者拷贝运算符的重载函数拷贝的不只是地址,而是数据。由于我们重新存储了一份数据,这样一个实例删除的时候,对另外一个实例没有影响。这种思路我们称之为深度拷贝。实现的代码如下:
public: Array(const Array& copy):data(0), size(copy.size) { if(size > 0) { data = new T[size]; for(int i = 0; i < size; ++ i) setValue(i, copy.getValue(i)); } } const Array& operator = (const Array& copy) { if(this == ©) return *this; if(data != NULL) { delete []data; data = NULL; } size = copy.size; if(size > 0) { data = new T[size]; for(int i = 0; i < size; ++ i) setValue(i, copy.getValue(i)); } }
为了防止有多个指针指向的数据被多次删除,我们还可以保存究竟有多少个指针指向该数据。只有当没有任何指针指向该数据的时候才可以被删除。这种思路通常被称之为引用计数技术。在构造函数中,引用计数初始化为1;每当把这个实例赋值给其他实例或者以参数传给其他实例的构造拷贝函数的时候,引用计数加1,因为这意味着又多了一个实例指向它的data;每次需要调用析构函数或者需要把data赋值为其他数据的时候,引用计数要减1,因为这意味着指向它的data的指针少了一个。当引用计数减少到0的时候,data已经没有任何实例指向它了,这个时候就可以安全地删除。实现的代码如下:
public: Array(unsigned arraySize) :data(0), size(arraySize), count(new unsigned int) { *count = 1; if(size > 0) data = new T[size]; } Array(const Array& copy) : size(copy.size), data(copy.data), count(copy.count) { ++ (*count); } ~Array() { Release(); } const Array& operator = (const Array& copy) { if(data == copy.data) return *this; Release(); data = copy.data; size = copy.size; count = copy.count; ++(*count); } private: void Release() { --(*count); if(*count == 0) { if(data) { delete []data; data = NULL; } delete count; count = 0; } } unsigned int *count;
发表评论
-
微软等数据结构+算法面试100题
2011-02-23 17:48 1948微软等100题系列V0.1版终于结束了。 从2010年10月 ... -
百度11月4日网上笔试题及答案
2010-10-27 22:27 1233编程: 用C语言实现一个revert函数,它的功能是将输入的字 ... -
程序员面试题精选(18)-用两个栈实现队列
2009-08-15 12:01 1914题目:某队列的声明如 ... -
程序员面试题精选(17)-把字符串转换成整数
2009-08-15 12:00 2399题目:输入一个表示整数的字符串,把该字符串转换成整数并输出。例 ... -
程序员面试题精选(16)-O(logn)求Fibonacci数列
2009-08-15 11:59 2623题目:定义Fibonacci数列如下: / ... -
程序员面试题精选(14)-圆圈中最后剩下的数字
2009-08-15 11:55 2324题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始 ... -
程序员面试题精选(13)-第一个只出现一次的字符
2009-08-15 11:52 1741题目:在一个字符串中找到第一个只出现一次的字符。如输入abac ... -
程序员面试题精选(12)-从上往下遍历二元树
2009-08-15 11:49 1202题目:输入一颗二元树,从上往下按层打印树的每个结点,同一层中按 ... -
程序员面试题精选(11)-求二元查找树的镜像
2009-08-15 11:43 1221题目:输入一颗二元查 ... -
程序员面试题精选(10)-在排序数组中查找和为给定值的两个数字
2009-08-15 11:40 1935题目:输入一个已经按升序排序过的数组和一个数字,在数组中查找两 ... -
程序员面试题精选(09)-查找链表中倒数第k个结点
2009-08-15 11:30 1737题目:输入一个单向链表,输出该链表中倒数第k个结点。链表的倒数 ... -
程序员面试题精选(08)-求1+2+...+n
2009-08-08 21:18 2658题目:求1+2+…+n,要求 ... -
程序员面试题精选(07)-翻转句子中单词的顺序
2009-08-08 21:17 1920题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺 ... -
程序员面试题精选(06)-判断整数序列是不是二元查找树的后序遍历结果
2009-08-08 21:15 1532题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历 ... -
程序员面试题精选(05)-查找最小的k个元素
2009-08-08 21:14 1749题目:输入n个整数,输出其中最小的k个。 例如输入1,2,3, ... -
程序员面试题精选(04)-在二元树中找出和为某一值的所有路径
2009-08-08 21:12 1302题目:输入一个整数和一棵二元树。从树的根结点开始往下访问一直到 ... -
程序员面试题精选(03)-求子数组的最大和
2009-08-08 21:10 1913题目:输入一个整形数组,数组里有正数也有负数。数组中连续的一个 ... -
程序员面试题精选(02)-设计包含min函数的栈
2009-08-08 21:08 1822题目:定义栈的数据结构,要求添加一个min函数,能够得到栈的最 ... -
程序员面试题精选(01)-把二元查找树转变成排序的双向链表
2009-08-08 20:58 1941题目:输入一棵二元查 ...
相关推荐
面试题6:简述类成员函数的重写、重载和隐藏的区别 面试题7:简述多态实现的原理 第10章 数据结构 10.1 链表 面试题1:链表和数组有什么区别 面试题2:寻找单链表中间结点 面试题3:怎样把一个单链表反序 10.2 单...
15. **含有指针成员的类的拷贝**:处理含有指针的类的深拷贝和浅拷贝问题,需要重载赋值运算符和复制构造函数,确保指针成员被正确复制和释放。 16. **Fibonacci数列的O(logn)求解**:使用矩阵快速幂可以在对数时间...
"C++程序员面试题集" 本文档总结了C++基础知识,涵盖了面试过程中可能出现的所有问题。下面是从文件中提炼出的相关知识点: 1. 面向对象的程序设计思想是什么? 答:把数据结构和对数据结构进行操作的方法封装形成...
"C或C++语言程序员面试精选"提供了一份宝贵的资源,旨在帮助开发者准备面试,并深化对这两种语言的理解。这份文档不仅适用于正在寻找工作的程序员,也适合任何希望巩固C/C++基础的学习者。 C语言,由Dennis Ritchie...
友元关系允许一个类访问另一个类的私有和保护成员,但这种关系是非对称的、不可传递的,且不能被继承。这意味着友元关系只能在声明中指定的类之间生效,不会自动扩展到子类或其他类。 #### 25. 对象成员初始化的...
【Linux程序员面试知识点详解】 1. **Linux发行版与软件版本**: Linux有众多发行版,如Ubuntu、CentOS、Fedora、Debian等。GCC(GNU Compiler Collection)是Linux下的编译器,用于将源代码编译为可执行程序。...
这份“笔试题-经典LINUX程序员面试题.pdf”涵盖了Linux程序员所需掌握的关键知识点,包括基础题、程序阅读题、程序写作题、英语基础题和选择题。以下是各部分的主要内容: **一、基础题** 1. **Linux发行版和版本...
《C/C++程序员面试宝典》是一本专为准备C/C++编程面试的求职者精心编写的指南。这本书以PDF格式提供,具有清晰的目录结构,使得读者可以快速定位到感兴趣或需要复习的知识点,有助于高效学习和查阅。在追求理想的...
### C++程序员面试300题相关知识点解析 #### 面向对象的程序设计思想 面向对象的程序设计(Object-Oriented Programming, OOP)是一种编程范式,其核心思想是将程序中的数据和操作这些数据的方法组织在一起,形成一...
【C/C++程序员应聘常见面试题】通常涵盖了基础语法、内存管理、字符串处理、指针操作、算法和数据结构等多个方面。以下是一些常见的知识点: 1. **字符串处理**: - **strcpy函数**:面试中常问的问题是要求应聘者...
这份"c++面试题汇总"集合了程序员宝典、面试试题和C++面试宝典等多个资源,旨在帮助求职者全面准备C++相关的面试。以下将对一些关键知识点进行详细阐述: 1. **基础语法**: - **变量与数据类型**:理解基本数据...
- **子类中的成员**: 派生类包含了基类的所有非私有成员(static成员除外),这意味着它可以访问基类的公有和受保护成员。 #### 4. 字符串中最长连续重复子串 - **知识点**: 查找字符串中最长连续重复子串的方法。 ...
### 深圳市雁联计算系统有限公司C++程序员面试题解析 #### 1. 栈与堆的申请方式及系统响应方式的区别 在C++编程中,**栈**和**堆**是两种不同的内存区域,它们在申请方式和系统响应上存在显著差异。 - **栈**内存...
总结来说,C/C++面试题通常涵盖语言基础、内存管理、数据结构、算法等多个方面。通过分析这些题目,程序员不仅可以检验自己的技术功底,还能发现自身的不足,进而提高编程技能。无论是在面试还是日常开发中,对细节...
《C/C++程序员应聘常见面试题深入剖析》 在C/C++编程领域,面试往往是对开发者基础技能和问题解决能力的直接检验。一道看似简单的题目,如要求编写一个`strcpy`函数,实则是对程序员对内存管理、字符串处理以及安全...
第1部分 求职过程 章 应聘求职 1.1 渠道 1.2 流程 第2章 简历书写 2.1 简历注意事项 2.2 简历模板 第3章 求职五步曲 3.1 笔试 3.2 电话面试 ...第5部分 综合面试题 附录A 面试经历总结
《C、C++程序员应聘常见面试题深入剖析》 面试是评估程序员技能的重要环节,尤其在C和C++这样的编程语言领域,面试题往往聚焦于基础概念和技术深度。本文将探讨一些常见的C/C++面试题,并通过具体示例来解析其中...
在C和C++的世界里,面试题通常涵盖了广泛的主题,从基本语法到高级设计原则,再到内存管理和模板元编程。以下是一些常见的C++面试题及其解析,它们可以帮助你为面试做好充分准备。 1. **指针与引用** - 指针是C++...