C++编程调试秘笈----一些杂项
1、避免编写拷贝构造函数和赋值操作符,如果默认版本并不适用,可以考虑把拷贝构造函数和赋值操作符声明为私有,禁止类实例的复制2、避免在析构函数中编写代码需要析构函数的原因可能有好几个:a、在基类中,可能需要声明虚拟析构函数,这样就可以使用一个指向基类的指针指向一个派生类的实例b、在派生类中,并不需要把析构函数声明为虚拟函数,但是为了增加可读性,也可以这样做c、可能需要声明析构函数并不抛出任何异常下来讨论一下为什么析构函数应该是空的:[cpp]class Student{public:Student{if (!number_){number_ = new int(age);}}~Student(){if (number_){delete number_;}}private:int* number_;};看看这个Student类,因为他在构造函数中获取了一些资源,所以需要在析构函数中释放掉。但是现在问题来了,这个类的设计----每次添加一个表示个人描述的新元素(例如number_)时,都需要在析构函数中添加对应的清理代码,这就违背了“不要迫使程序员记住某些事情”的原则;另一个问题是,缺少安全检查,首先你的number_可能是要必须大于0的,这样还得在new的前面进行if判断,另外一个极端的情况:[cpp]#include "stdafx.h"#include "iostream"#include "string"class A{public:A() { std::cout << "Creating A" << std::endl; }~A(){ std::cout << "Destroying A" << std::endl; }};class B{public:B() { std::cout << "Creating B" << std::endl; }~B(){ std::cout << "Destroying B" << std::endl; }};class C : public A{public:C(){std::cout << "Creating C" << std::endl;throw "Don't like C";}~C(){ std::cout << "Destroying C" << std::endl; }private:B b_;};int _tmain(int argc, _TCHAR* argv[]){try{C c;}catch (...){std::cout << "Caught an exception" << std::endl;}return 0;}因为在C中throw了一个异常,所以导致class C的析构函数没有被执行,这就导致了一些问题的产生改成下面的形式设计就要好得多:[cpp]class Student{public:Student(const int number, const char* name){SCPP_ASSERT(number > 0, "number must be large 0");number_ = new int(number);SCPP_ASSERT(name != NULL, "name must be not null");name_ = new std::string(name);}~Student(){}private:Student(const Student& student);Student& operator = (const Student&);scpp::ScopedPtr<int> number_;scpp::ScopedPtr<std::string> name_;};即使第二个安全检查抛出异常,执行name_的智能指针的析构函数仍然会被调用,并执行他的清理工作。另一个附带的好处是,我们并不需要操心把这些智能指针初始化为NULL,这是自动完成的。因此,可以看到构造函数抛出异常是一种潜在的危险行为;对应的析构函数将不会被调用,因此可能会存在问题,除非析构函数是空函数。3、编写一致的比较操作符常用的操作符有< > <= >= == !=,站在C++的角度,这些操作可以写成6个相互完全独立的函数,但是他们相互之间又有联系,比如x1>x2成立,x2<x1和x1>=x2也是成立的。所以,我们需要一些步骤来帮我实现这个目标(往之前的scpp_types.h上面添加):[cpp]#ifndef __SCCP_TYPES_H__#define __SCCP_TYPES_H__#include <ostream>#include "scpp_assert.h"template <typename T>class TNumber{public:TNumber(const T& x =0 ):data_(x){}operator T() const{return data_;}TNumber &operator = (const T& x){data_ = x;return *this;}TNumber operator ++(int){TNumber<T> copy(*this);++data_;return copy;}TNumber operator ++(){++data_;return *this;}TNumber& operator += (T x){data_ += x;return *this;}TNumber& operator -= (T x){data_ -= x;return *this;}TNumber& operator *= (T x)补充:软件开发 , C++ ,
上一个:cortex m3 LPC1768 sprintf %f 出现崩溃 硬件错误 reset 原因是 arm-gcc 不支持 sprintf %f
下一个:C++编程调试秘笈----带有初始化的基本类型
- 更多C/C++疑问解答:
- 关于c++的cout输出的问题。
- 在学校里学过C和C++,不过学的很一般,现在自学C#,会不会很难?
- 全国计算机二级C语言笔试题
- 已知某树有2个2度结点,3个3度结点,4个4度结点,问有几个叶子结点?
- c++数据结构内部排序问题,整数排序
- 2012九月计算机二级C语言全国题库,,急求急求
- 如果assert只有一个字符串作为参数,是什么意思呢?
- C语言中,哪些运算符具有左结合性,哪些具有右结合性,帮忙总结下,谢谢了!
- 为什么用结构体编写的程序输入是,0输不出来啊~~~
- 将IEEE—754的十六进制转化为十进制浮点类型,用C或C++都行,多谢各位大侠啊,非常感谢!
- 为什么这个程序求不出公式?
- 这个链表倒置的算法请大家分析下
- c语言函数库调用
- C语言unsigned int纠错
- C语言快排求解啊