Effective C++ 重要条款

     学习c++的童鞋们,这本书不能错过,最近在学校图书馆借来这本书,准备好好啃啃它了,先把它的基本内容过一遍吧。

改变旧有的的C习惯

  条款1:尽量以const和inline取代#define。

  条款2:尽量以<iostream>取代<stdio.h>

  条款3:尽量以new和delete取代malloc和free。

  条款4:尽量使用C++风格的注释形式。

  条款5:使用相同形式的new和delete。

内存管理篇

  条款6:记得在destructor中以delete对付pointer  members。

  条款7:为内存不足的状况预做准备。

  条款8:撰写operator new和operator delete 时应遵行的公约。

  条款9:避免遮掩了new的正规形式。

  条款10:如果你写了一个operator new,请对应写一个operator delete。

      对于条款1就没什么好说的了,建议我们不要使用宏,改用常量,如const double ASPECT_RACIO=1.653,取代define  ASPECT_RACIO   1.653。

      条款2是对于输入输出而言,我们应该尽量采用cin,cout。

      条款3说明在c++中尽量用new取代malloc,如string *stringArray2=new string[10],当释放内存时delete[]stringArray2,数组中的每个对象的destructor都会被调用一遍。

      条款10对于分配内存进行了详细的说明,我们自己写operator new的时候,一定不要忘了写operator  delete,否则就Memory leak了。

下面看段代码,书上说的是写一个Pool类来配置内存,由它负责申请和释放内存,首先定义一个Pool类。

class  Pool
{
public:
	Pool(size_t n);    //首先声明需要空间的大小
	void *alloc(size_t n);   //申请内存
	void free(void *p,size_t n);  //释放内存
	~ Pool();
};

class  AirPlane
{
public:
	 AirPlane();
	~ AirPlane();
	static void* operator new(size_t size);    
	static void operator delete(void *p,size_t size);

private:
	AirPlaneRep* rep;
	static Pool memPool;

};

inline void* AirPlane::operator new(size_t size)
{
	return memPool.alloc(size);
}
inline  void AirPlane::operator delete(void *p,size_t size)
{
	return  memPool.free(p,size);
}

 Pool  AirPlane::memPool(sizeof(AirPlane));   //用sizeof()初始化memPool,大小为一个Airplane;

 通过这种方法可以改善程序效率,重点还是需要operator new和operator delete 二者合作。

条款11:如果class内动态配置有内存,请为此class声明一个copy constructor和一个assignment运算符。这就话也可以这么理解,当你的class中拥有任何指针的时候,那么类最好拥有自己的copy constructor和assignment operator。

class  TableString
{
public:
	 TableString(const char*);  
	~ TableString();

private:
	char* data;
};

 TableString:: TableString(const char*value)
{
	if (value)
	{
		data=new char[strlen(value)+1];
		strcpy_s(data,strlen(value)+1,value);
	} 
	else
	{
		data=new char[1];
		*data='';
	}
}

 TableString::~ TableString()
{
	delete[]data;
}
int _tmain(int argc, _TCHAR* argv[])
{
	TableString a("hello");
	TableString b("nihao");
	b=a;
	return 0;
}

  例如上面这段代码里面,类TableString有自己的指针变量,却没有定义自己的复制构造函数和赋值函数,当执行完b=a这一句的时候,内存就已经泄漏了。首先,b原先的内存没有释放,其次,a和b的指针指向相同的字符串,当其中一个离开生存空间,就会调用它的析构函数,删除内存,另外一个指针指向的内存就为空了。

构造、析构和赋值操作

条款15:令operator==传回“*this的reference”

String& String::operator=(const String& rhs)
{
	return *this; //传回一个引用,指向左侧对象
}
String&  String::operator=(const String& rhs)
{
	return   rhs;   //指向右侧对象
}

  定义的第二个赋值操作符将无法通过编译,因为rhs是一个引用型const常量,而传回的却是非const引用,而我们把const去掉的话也不能解决问题,不能把const常量传递给非const的参数变量。所有,我们别无选择,只能return *this。

条款16:在operator=中为所有的datamembers设定(赋值)内容

    这个条款大概的意思就是在派生类中必须对基类的成员进行一个初始化,在派生类的构造函数中可以调用基类的构造函数进行成员的初始化,为base制定初值。

条款17:在operator=中检查是否“自己赋值给自己”   

    成员在赋值的时候,又可能出现自己赋值给自己的情况,例如:String a="hello world";a=a;如果你在赋值运算符中没有对这个进行检验的话,那么程序写出来后果将不堪设想。我们一般的做法是看它们的内存地址是否相等。例如:

C& C::operator=(const C& rhs)
{
	if (this==&rhs)
	{
		return *this;
	}
}

  这对许多程序而言都足够了。

原文地址:https://www.cnblogs.com/master-image/p/3816936.html