本文介绍了 C++ 的 5 个特别用法(Idioms),分别是
Concrete Data Type; Lazy Evaluation; Copy and Swap; Copy on Write; Reference Counting;
06. Concrete Data Type
用途
通过允许或禁止动态内存分配来控制对象的生存期和作用域
示例代码
只允许通过动态内存分配的方式创建对象(方法一)
class EventHandler
{
public :
virtual ~ EventHandler ( ) { }
} ;
class MouseEventHandler : public EventHandler
{
public :
MouseEventHandler ( ) { }
protected :
~ MouseEventHandler ( ) { }
} ;
int main ( ) {
MouseEventHandler mouse;
EventHandler* event_handler = new MouseEventHandler ( ) ;
delete event_handler;
return 0 ;
}
只允许通过动态内存分配的方式创建对象(方法二)
class MouseEventHandler : public EventHandler
{
public :
static MouseEventHandler* create ( )
{ return new MouseEventHandler ( ) ; }
void distroy ( ) { delete this ; }
protected :
MouseEventHandler ( ) { }
~ MouseEventHandler ( ) { }
} ;
只允许创建自动对象
class ScopeLock
{
private :
static void * operator new ( size_t size) ;
static void * operator new ( size_t size, void * mem) ;
} ;
07. Lazy Evaluation
用途
等到真正要使用时才构造对象,尤其是非局部对象 常用于 Singleton 模式
示例代码
问题:访问未初始化的非局部静态对象
class Bar
{
public :
Bar ( ) { cout << "Bar::Bar()" << endl; }
void func ( ) { cout << "Bar::func()" << endl; }
} ;
class Foo
{
public :
Foo ( ) { bar. func ( ) ; }
static Bar bar;
} ;
Foo foo;
Bar Foo:: bar;
int main ( ) {
return 0 ;
}
解决方法一:通过动态分配内存创建对象
class Foo
{
public :
Foo ( ) { bar ( ) . func ( ) ; }
Bar& bar ( ) {
static Bar* b = new Bar ( ) ;
return * b;
}
} ;
Foo foo;
int main ( ) {
return 0 ;
}
解决方法二:创建自动对象
class Foo
{
public :
Foo ( ) { bar ( ) . func ( ) ; }
Bar& bar ( ) {
static Bar b;
return b;
}
} ;
Foo foo;
int main ( ) {
return 0 ;
}
08. Copy and Swap
用途
示例代码
不进行自赋值检查
class String
{
char * str;
public :
String& operator = ( const String& s) {
String temp ( s) ;
temp. swap ( * this ) ;
return * this ;
}
void swap ( String& s) throw ( ) {
std:: swap ( this - > str, s. str) ;
}
} ;
进行自赋值检查
class String
{
char * str;
public :
String& operator = ( const String& s) {
if ( this != & s) String ( s) . swap ( * this ) ;
return * this ;
}
void swap ( String& s) throw ( ) {
std:: swap ( this - > str, s. str) ;
}
} ;
09. Copy on Write
用途
示例代码
template < typename T>
class CowPtr
{
public :
CowPtr ( T* t) : m_sp ( t) { }
CowPtr ( shared_ptr< T> t) : m_sp ( t) { }
CowPtr ( const shared_ptr< T> & r) : m_sp ( r) { }
const T& operator * ( ) const { return * m_sp; }
T& operator * ( ) { detach ( ) ; return * m_sp; }
const T* operator - > ( ) const { return m_sp. operator - > ( ) ; }
T* operator - > ( ) { detach ( ) ; return m_sp. operator - > ( ) ; }
private :
void detach ( ) {
T* tmp = m_sp. get ( ) ;
if ( ! ( tmp == nullptr || m_sp. unique ( ) ) )
m_sp = shared_ptr< T> ( new T ( * tmp) ) ;
}
private :
shared_ptr< T> m_sp;
} ;
10. Reference Counting
用途
引用计数,当多个指针或引用指向同一个对象时,应该由谁负责销毁操作
示例代码
class StringRep
{
friend class String ;
friend ostream& operator << ( ostream& os, const StringRep& rep) {
os << "[" << rep. data << ", " << rep. count << "]" ;
return os;
}
public :
StringRep ( const char * s) : count ( 1 ) {
strcpy ( data = new char [ strlen ( s) + 1 ] , s) ;
}
~ StringRep ( ) { delete [ ] data; }
private :
size_t count;
char * data;
} ;
class String
{
public :
String ( ) : rep ( new StringRep ( "" ) ) {
cout << "default constructor: " << * rep << endl;
}
String ( const String& s) : rep ( s. rep) {
rep- > count++ ;
cout << "copy constructor: " << * rep << endl;
}
String ( const char * s) : rep ( new StringRep ( s) ) {
cout << "construct by const char*: " << * rep << endl;
}
String& operator = ( const String& s) {
cout << "before assign: " << * s. rep << " to " << * rep << endl;
String ( s) . swap ( * this ) ;
cout << "after assign: " << * s. rep << ", " << * rep << endl;
return * this ;
}
~ String ( ) {
if ( rep && rep- > count <= 1 ) {
cout << "destructor: " << * rep << endl;
delete rep;
}
}
private :
void swap ( String& s) throw ( ) { std:: swap ( rep, s. rep) ; }
private :
StringRep* rep;
} ;
int main ( ) {
String str1;
{
str1 = "ABC" ;
String str2 ( str1) ;
}
str1 = "CBA" ;
return 0 ;
}