Effective C++ 学习笔记
2011-07-27 21:20 Clingingboy 阅读(653) 评论(0) 编辑 收藏 举报
基于此文档
http://wenku.baidu.com/view/ef989106e87101f69e3195db.html
条款13:以对象管理资源
目标:为确保资源被释放
1.获得资源后立即放进管理对象
2.管理对象运用析构函数确保资源被释放
做法:
之前
void f()
{
Investment *pInv = createInvestment(); // call factory function
... // use pInv
delete pInv; // release object
}
之后
void f()
{
std::auto_ptr<Investment> pInv(createInvestment());
}
关于std::auto_ptr和std::tr1::shared_ptr用法不再叙述
条款14:在资源管理类中小心coping行为
class Lock {
public:
explicit Lock(Mutex *pm)
: mutexPtr(pm)
{ lock(mutexPtr); } // acquire resource
~Lock() { unlock(mutexPtr); } // release resource
private:
Mutex *mutexPtr;
};
coping行为
Lock ml1(&m); // lock m
Lock ml2(ml1);
问题:“当一个RAII对象被复制,会发生什么事?”
选择做法:
1.禁止复制
class Lock: private Uncopyable { // prohibit copying — see
public: // Item 6
... // as before
};
2.(最为普遍方法)利用std::tr1::shared_ptr的删除器做引用计数(当计数为0时调用的函数,但不删除指针)
class Lock {
public:
explicit Lock(Mutex *pm) // init shared_ptr with the Mutex
: mutexPtr(pm, unlock) // to point to and the unlock func
{ // as the deleter
lock(mutexPtr.get()); // see Item 15 for info on "get"
}
private:
std::tr1::shared_ptr<Mutex> mutexPtr; // use shared_ptr
};
3.深拷贝资源,但不用时要做删除动作
4.利用auto_ptr做资源拥有权的转移
条款15:在资源管理类中提供对原始资源的访问
如下代码
std::tr1::shared_ptr<Investment> pInv(createInvestment()); // from Item 13
int daysHeld(const Investment *pi); // return number of days
int days = daysHeld(pInv); // error!
int days = daysHeld(pInv.get());
两种方式:
1.显示转换:get方法就是显示转换
class Font { // RAII class
public:
... // C API does
FontHandle get() const { return f; }
private:
FontHandle f; // the raw font resource
...
};
changeFontSize(f.get(), newFontSize); // explicitly convert
2.隐式转换
class Font {
public:
...
operator FontHandle() const { return f; } // implicit conversion function
...
};
changeFontSize(f, newFontSize); // implicitly convert
显然各有优缺点,但显示转换不易被误用,如std: string的显示转换方法
条款17:以独立语句将newd对象置入智能指针
int priority();
void processWidget(std::tr1::shared_ptr<Widget> pw, int priority);
如何传参的问题:
重点:保证传入的指针在异常的时候可以释放资源
processWidget(std::tr1::shared_ptr<Widget>(new Widget), priority());
以上做法可能有错误,如果执行顺序如下,而priority函数发生了错误,那么内存无法释放
-
Execute "new Widget".
-
Call priority.
-
Call the tr1::shared_ptr constructor.
保险的做法,在外部声明
std::tr1::shared_ptr<Widget> pw(new Widget); // store newed object
processWidget(pw, priority()); // this call won't leak
第四章:设计与声明
这一章大多与设计有关
条款18:让接口容易被正确使用,不易被误用
让接口更易被理解和使用
之前:
class Date {
public:
Date(int month, int day, int year);
...
};
以类代替(请勿模仿,任何事物防不胜防,看需求而定)
struct Day { struct Month { struct Year {
explicit Day(int d) explicit Month(int m) explicit Year(int y)
:val(d) {} :val(m) {} :val(y){}
int val; int val; int val;
}; }; };
class Date {
public:
Date(const Month& m, const Day& d, const Year& y);
...
};
Date d(30, 3, 1995); // error! wrong types
Date d(Day(30), Month(3), Year(1995)); // error! wrong types
Date d(Month(3), Day(30), Year(1995)); // okay, types are correct
条款 21:必须返回对象时,别妄想返回其reference
拒绝一下两种写法,c#和java的开发者一定很不习惯
const Rational& operator*(const Rational& lhs, // warning! bad code!
const Rational& rhs)
{
Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
return result;
}
const Rational& operator*(const Rational& lhs, // warning! more bad
const Rational& rhs) // code!
{
Rational *result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
return *result;
}
必须要返回对象是,请返回一个新对象
inline const Rational operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
}
条款 22:将成员变量声明为private
真的没什么好讲的,学过c#和java的人都知道
class AccessLevels {
public:
...
int getReadOnly() const { return readOnly; }
void setReadWrite(int value) { readWrite = value; }
int getReadWrite() const { return readWrite; }
void setWriteOnly(int value) { writeOnly = value; }
private:
int noAccess; // no access to this int
int readOnly; // read-only access to this int
int readWrite; // read-write access to this int
int writeOnly; // write-only access to this int
};
条款 23:宁以non-member、non-friend替换member函数
class WebBrowser {
public:
...
void clearCache();
void clearHistory();
void removeCookies();
//void clearBrowser(WebBrowser& wb)
//{
// wb.clearCache();
// wb.clearHistory();
// wb.removeCookies();
//}
...
};
void clearBrowser(WebBrowser& wb)
{
wb.clearCache();
wb.clearHistory();
wb.removeCookies();
}
将便利函数放在外部,不要为类添加太多的类成员(意思就是只添加必要的),基本属于设计问题
条款 24:若所有参数皆需类型转换,请为此采用non-member函数
如下示例代码
class Rational {
public:
Rational(int numerator = 0, // ctor is deliberately not explicit;
int denominator = 1); // allows implicit int-to-Rational
// conversions
int numerator() const; // accessors for numerator and
int denominator() const; // denominator — see Item 22
const Rational operator*(const Rational& rhs) const;
private:
...
};
其提供了隐式转换功能:
Rational oneEighth(1, 8);
Rational oneHalf(1, 2);
Rational result = oneHalf * oneEighth; // fine
result = result * oneEighth; // fine
更加贪婪的做法
result = oneHalf * 2; // fine
result = 2 * oneHalf; // error!
为了支持2的隐式转换,做法是实现一个non-member的操作符重载
const Rational operator*(const Rational& lhs, // now a non-member
const Rational& rhs) // function
{
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
Rational oneFourth(1, 4);
Rational result;
result = oneFourth * 2; // fine
result = 2 * oneFourth; // hooray, it works!
记得是所有参数