Ôn lại lý thuyết : quá trình sinh ra và chết đi của một object thuộc một class Foo nào đó .

Quá trình tạo ra object :

  • 1. Cấp phát "raw" memory cho object : các trường hợp sau có thể xảy ra
    • A1. Cấp phát bộ nhớ theo kiểu tĩnh
    • A2.Cấp bộ nhớ theo kiểu động với các operator new hoặc new[] : nếu class có các toán tử new thì dùng toán tử của class, nếu không, dùng new hoặc new[] của "compiler"
  • 2 . Gọi contructor tương ứng và object đã được tạo ra


Quá trình object chết đi :
  • 3. Gọi destructor
  • 4. Trả lại memory : các trường hợp có thể xảy ra
    • D1: Nếu đã cấp phát tĩnh : trả lại memory được thực hiện bởi compiler
    • D2: Nếu đã cấp phát động : dùng operator delete hoặc delete [] của class Foo nếu có, nếu không dùng version ::new hoặc ""new[] của "compiler"


Nhận xét : trong những bước ở trên, những "bước" có màu xanh hoặc màu hồng là những bước chúng ta có thể ngăn chặn để chúng không xảy ra đối với người sử dụng bình thường. Cách ngăn chặn là để method hoặc toán tử tương ứng vào loại "protected" hoặc "private" . Ví dụ : để không thể cấp phát memory động cho object , chúng ta khai báo các operater new, new[] của class và để chúng dưới dạng private .
PHP Code:
class Foo
                 
{
                 public:
                     
//public interface ...

                 
private:
                     
void *operator new (size_t);
                     
void *operator new[] (size_t);
                 }; 
Khi đó, người sử dụng bình thường không thể dùng câu lệnh sau được

PHP Code:
Foo *obj = new Foo
vì nếu dùng, compiler sẽ báo lỗi :

'new' : cannot access private member declared in class 'Foo'

Như vậy bằng cách ngăn chặn một số "bước" nào đó trong quá trình tạo ra và chết đi của object, chúng ta có thể tạo ra một class mà object của nó chỉ dưới dạng cấp phát tĩnh hoặc chỉ dưới dạng cấp phát động mà thôi . Sau đây là lời giải cụ thể .

Phần 1: Chỉ dùng cấp phát tĩnh mà thôi : ngăn chặn không cho bước A2 xảy ra, khi đó người dùng bình thường không thể dùng new . [ Nếu cẩn thận chúng ta cũng ngăn chặn luôn bước D2, để người dùng không thể dùng delete ]

PHP Code:
class OnlyOnStack
        
{
        public:
            
//public interface ...
       
        
private:
            
void *operator new (size_t);
            
void *operator new[] (size_t);

            
void  operator delete (void*);
            
void  operator delete[] (void*);
       
       
        private:
            
int data;
       
        };
       
        
void Test_OnlyOnStack()
        {
           
            
OnlyOnStack obj;
            
OnlyOnStack ArrObj[10];
       
            
// OnlyOnStack *pObj   = new OnlyOnStack;
            //
            // ==> Compiler Error : 
            //
            // error C2248: 'new' : cannot access private member
            // declared in class 'OnlyOnStack'
       
       
            // OnlyOnStack *pArrObj = new OnlyOnStack[10];
            //
            // ==> Compiler Error : 
            //
            // error C2248: 'new[]' : cannot access private member
            // declared in class 'OnlyOnStack'
       
        

Phần 2. Chỉ dùng cấp phát động mà thôi :

Muốn cấp phát tĩnh không xảy ra, chúng ta phải ngăn chặn không cho contructor hoặc destructor xảy ra đối với người sử dụng bình thường . Thông thường một class có thể có nhiều constructor, tuy nhiên chỉ có tối đa một destructor . Do đó, chúng ta quyết định sẽ ngăn chặn destructor từ người sử dụng bình thường, vì vậy người sử dụng sẽ không thể dùng delete được và chúng ta cũng cung cấp những function khác để người sử dụng có thể dùng những function mới này mà phá hũy các object. Cách giải này có phần hạn chế là user sẽ không được dùng delete để phá hủy object của class cần cài đặt, nếu không sẽ bị compiler error . Sau đây là code minh hoạ:

PHP Code:
 class OnlyOnFreeStore
        
{
        public:
       
            
//public interface ...
       
            
static void deleteSingle(OnlyOnFreeStorep)
            {
                
delete p;
            }
       
            static 
void deleteArray(OnlyOnFreeStorearr)
            {
                
delete[] arr;
            }
       
        private:
            
//destructor
            
~OnlyOnFreeStore()
            {
            }
       
            
int data;
       
        };
       
       
        
void Test_OnlyOnFreeStore()
        {
           
            
OnlyOnFreeStore *= new OnlyOnFreeStore;
            
OnlyOnFreeStore::deleteSingle);
       
       
            
OnlyOnFreeStore *arrFreeStore = new OnlyOnFreeStore[20];
            
OnlyOnFreeStore::deleteArrayarrFreeStore );
       
            
// OnlyOnFreeStore obj;
            //
            // ==> Compiler Error : 
            //
            // error C2248: 'OnlyOnFreeStore::~OnlyOnFreeStore' :
            // cannot access private member declared in class 'OnlyOnFreeStore'
       
       
            // OnlyOnFreeStore arrObj[10];
            //
           // VC++ bug : VC++ đã không  báo lỗi khi cấp phát tĩnh
           // một array như trên . Tuy nhiên Borland C++ ... đã báo lỗi .
               
        

Có bạn hỏi : tại sao phải quan tâm tới việc "chỉ cấp phát tĩnh hay chỉ cấp phát động" trong câu hỏi này.

Trả lời, có nhiều trường hợp người cài đặt một class nào đó mong muốn người sử dụng chỉ được tạo ra object từ lớp đó bằng cấp phát động mà thôi . Ví dụ, class dùng counter để duy trì đời sống của object , khi object được tạo ra nó có counter bằng 1, nếu ai muốn dùng nó thì tăng counter lên, không muốn dùng thì giảm counter xuống . Nếu counter = 0 thì dùng delete để phá hủy object . Chuyện này chỉ hợp lệ khi cấp phát động . Tuy nhiên nếu người sử dụng cấp phát tĩnh sẽ khiến chương trình bị bug vì đã delete một pointer chỉ tới memory của stack . Nếu chúng ta có cách khiến compiler phát hiện ra lỗi sai thì rất tốt, nếu không phải debug vất vả mới tìm ra lỗi . [ Trong lập trình cho COM/ActiveX, người ta hay dùng counter kiểu này ]

Cũng cùng ý tưởng như trên, nhưng nếu biết object chỉ được cấp phát tĩnh , thì khi counter = 0 chúng ta chỉ cần giải phóng resource mà không cần delete object .

Trong OWL (Object Windows Language) của Borland C++ hay trong framework VCL của Borland C++ Builder, khi chúng ta tạo ra một button và add vào một dialog hay một form , thì dialog hoặc form đó giữ button object trong danh sách . Khi diaglog hoặc form đó destroy thì nó lấy các object trong danh sách ra và delete . Chuyện này chỉ đúng nếu các object tạo ra bằng cách cấp phát động .

Sưu tầm từ diendantinhoc.net