effective c++ item 25-29

item25:自定义swap函数

namespace std{
	template
	void swap(T& a, T& b){
		T temp(a);		// T要满足拷贝构造和拷贝赋值
		a = b;
		b = temp;		
	}
}

1、Pimpl

2、自定义swap

item26:尽可能延后变量的定义

case 1:
temp j;
for(int i = 0; i < n; ++ i){
	j = func(i);
}

case 2:
for(int i = 0; i < n; ++ i){
	temp j(i);
}

方案1调用了1次构造、1次析构和n次赋值
方案2调用了n次构造和n次析构
如果对程序效率不敏感,则方案2更好

item27:正确使用类型转换

1、c语言

(T) expression;
T(expression);

2、static_cast(expression)

int x, y;
double d = static_cast (x) / y;

// 自定义变量
class Widget{
public:
	explicit Widget(int size);
};
void dosomework(const Widget& w);

dosomework(Widget(15));			// function-style cast
dosomework(static_cast(15));	// c++ style cast
#include 
using namespace std;

class Base{
public:
    int a;
};

class Derived:public Base{
public:
    double c;
    virtual void bar(){}
};

void test(Base* base, Derived* derived){
    printf("%p, %p", base, derived);				// 0x16fab2c58, 0x16fab2c50
    printf("%p\n", static_cast(derived));	// 0x16fab2c58
    if(base == static_cast(derived)){
        cout << "==" << endl;						// == 
    }else{
        cout << "!=" << endl;
    }
}

int main(){
    Derived derived;
    test(&derived, &derived);	
    return 0;
}

类中含有虚指针,8个字节,staticcast会移动类的指针

3、dynamic_cast ()

在运行时类型转换,开销很大

4、const_cast()

5、reinterpret_cast()

item28:以引用的方式返回对象的成员

1、注意访问级别

以引用的方式返回的成员需要注意,因为可能会提高他的访问级别,导致被外部修改

class Point{
public:
	Point(int x, int y);

	void setX(int newVal);
	void setY(int newVal);
};

struct RectData{
	Point ulhc;		// upper left-hand corner
	Point lrhc;		// lower right-hand corner
};

class Rectangle{
public:
	Point& upperLeft() const { return pData->ulhc;}		// const承诺不修改其中的成员变量
	Point& lowerRight() const{ return pData->lrhc;}
private:
	std::shared_ptr pData;
};

int main(){
	Point coord1(0, 0);
	Point coord2(100, 100);
	const Rectangle rec(coord1, coord2);		// const表示成员状态不会变
	rec.upperLeft().setX(50);		// 由于upperLeft返回的是引用,再调用setx就把成员状态更改了
}

为了防止上边那种意料之外的修改,我们可以这样更改:

class Rectangle{
public:
	const Point& upperLeft() const { return pData->ulhc;}	// 增加const,返回一个const的指针
	const Point& lowerRight() const{ return pData->lrhc;}
private:
	std::shared_ptr pData;
};

2、访问未定义内存

class GUIObject {...};
const Rectangle boundingBox(const GUIObject& obj);

GUIObject *pgo;		// make pgo point to some GUIObject
const Point *pUperLeft = &(boundingBox(*pgo).upperLeft()); 
		// 返回一个临时变量的地址,在临时变量被释放后,操作pUperLeft会导致未定义行为

// 应当用一个变量接收
auto bbox = boundingBox(*pgo);
const Point* pUpperLeft = &(bbox.uperLeft());

item29:努力写出异常安全的代码

class Menu{
	Mutex mutex;
	Image *bgImage;
	int imageChanges;
public:
	void changeBackground(std::istream& imgSrc);
};

void Menu::changeBackground(std::istream& imgSrc){
	lock(&mutex);
	delete bgImage;
	++ imageChanges;
	bgImage = new Image(imgSrc);	// 如果这一步没有new成功,会导致资源泄漏(锁未释放)、数据损坏(背景被删除、改变次数+1)
	unlock(&mutex);
}

异常安全(exception-safe functions):

  • leak no resources
  • dont allow data structures to become corrupted

上面的代码应该这样修改:

class Menu{
	Mutex mutex;
	std::shared_ptr bgImage;
	int imageChanges;
public:
	void changeBackground(std::istream& imgSrc);
};

void Menu::changeBackground(std::istream& imgSrc){
	Lock ml(&mutex);		// item14:acquire mutex and ensure its later release(RAII)
	bgImage.reset(new Image(imgSrc));
	++ imageChanges;
}

你可能感兴趣的:(effective,c++,c++,开发语言)