Vietnamese Developers’ Blog

Lớp auto_ptr trong C++

Posted in C/C++ by kiennguyen on November 12, 2007

Nguồn: Tổng hợp từ Exceptional C++ của Herb Sutter và The C++ Standard Library của Nicolai M. Josuttis

auto_ptr là gì?

Các hàm trong các ngôn ngữ lập trình thường hoạt động theo quy trình sau đây

1- Cấp phát tài nguyên
2- Thực hiện các xử lí
3- Giải phóng tài nguyên

Nếu tài nguyên được cấp phát thông qua các đối tượng cục bộ, chúng sẽ được tự động giải phóng khi kết thúc hàm. Ngược lại, khi tài nguyên được cấp phát một cách tường minh và không gắn với một đối tượng nào, chúng phải được giải phóng một cách tường minh. Tài nguyên thường được cấp phát và giải phóng một cách tường minh thông qua các con trỏ. Cách sử dụng con trỏ phổ biến trong C++ là sử dụng toán tử new và delete như sau:

//Ví dụ 1(a): Đoạn mã không sử dụng auto_ptr
//
void f()
{
    T* pt( new T ); //Cấp phát tài nguyên một cách tường minh
    /*... các xử lí ...*/
    delete pt; //Giải phóng vùng nhớ pt trỏ tới một cách tường minh
} //Kết thúc hàm, biến cục bộ pt được hủy một cách tự động

Hàm f() mang trong mình một lỗi tiềm ẩn: Người lập trình có thể quên không viết câu lệnh delete. Kể cả trong trường hợp có lệnh delete, nếu có một lệnh return được viết trước đó hoặc xảy ra một exception thì hàm f sẽ thoát ngay lập tức mà không thực hiện lệnh delete. Các trường hợp này nếu xảy ra đều dẫn đến lỗi memory leak. Giải pháp thông thường là chúng phải bắt tất cả các exception có thể xảy ra.

void f()
{
    T* pt( new T ); //Cấp phát tài nguyên một cách tường minh
    try{
        /* ...Các xử lí, có thể xảy ra exception...*/
    } catch( ... ) { //Với mọi exception xảy ra:
        delete pt; //-giải phóng vùng nhớ pt trỏ tới
        throw; //-ném ra exception
    }

    delete pt; //Không xảy ra exception, giải phóng vùng nhớ pt trỏ tới

} //Kết thúc hàm, biến cục bộ pt được hủy một cách tự động

Giải pháp này sẽ trở nên phức tạp khi có nhiều tài nguyên được cấp phát một cách tường minh. Chúng ta cần một con trỏ “thông minh” (smart pointer) có khả năng tự giải phóng vùng nhớ mà nó đang trỏ đến bất cứ khi nào bản thân con trỏ đó bị hủy. Con trỏ cũng là một biến cục bộ nên nó sẽ bị hủy một cách tự động khi hàm thoát ra bất kể theo cách bình thường hay bất thường. Bởi vậy, khi kết thúc hàm hoặc ra khỏi phạm vi (scope) của con trỏ thông minh, vùng nhớ được cấp phát động trước đó sẽ tự động được giải phóng mà không cần đến câu lệnh delete nữa. Lớp auto_ptr ra đời nhằm đáp ứng nhu cầu này.

Một auto_ptr đóng vai trò như chủ sở hữu (owner) của một đối tượng được cấp phát động. Bất cứ khi nào một auto_ptr bị hủy, đối tượng mà nó đang sở hữu cũng bị hủy theo. Mỗi đối tượng chỉ được sở hữu bởi duy nhất bởi một auto_ptr. Đoạn mã trở nên đơn giản hơn nhiều nhờ sử dụng auto_ptr như sau: (more…)