2011-11-09 26 views
6

xây dựng hai giai đoạn có hình dạng như sau:Các con trỏ thông minh có ngăn cản sự cần thiết phải xây dựng hai pha không?

struct something { 
    something() 
     : p1(NULL) 
     , p2(NULL) 
    { } 

    ~something() { 
     if (p1) delete p1; 
     if (p2) delete p2; 
    } 

    void initialize() { 
     p1 = new int(2); 
     p2 = new int(5); // May throw if allocation fails! 
    } 

    int* p1; 
    int* p2; 
}; 

Điểm trong số đó là có một constructor ngây thơ (mà không xem cho thất bại phân bổ) sẽ bị rò rỉ bộ nhớ: destructor một đối tượng phần-xây dựng là không bao giờ được gọi .

Câu hỏi của tôi: là mã sau an toàn, và bằng cách sửa đổi, các con trỏ thông minh có làm giảm bớt việc xây dựng hai pha không?

struct something { 
    something() 
     : p1(new int(2)) 
     , p2(new int(5)) 
    { } 

    std::unique_ptr<int> p1; 
    std::unique_ptr<int> p2; 
}; 
+6

Bạn không cần điều kiện trước khi 'xóa'. Nghiêm túc, bạn không. Xóa bỏ null là hoàn toàn tốt đẹp. –

+0

Không có mới ném và xóa quá mà làm việc với phân bổ bộ nhớ giống như malloc()/miễn phí(). Nhưng ngay cả khi việc phân bổ chính nó không thất bại bằng cách sử dụng non-throwing new/delete, các nhà xây dựng đối tượng vẫn có thể ném. –

+0

@KerrekSB Lưu ý. :) –

Trả lời

5

Có, mã mới của bạn vẫn ổn. Tuy nhiên lưu ý rằng có một khả năng tinh tế trong các trường hợp phức tạp hơn:

#include <memory> 

struct foo { 
    foo(std::shared_ptr<int> a, std::shared_ptr<int> b) { } 
}; 

struct bar { 
    foo f; 
    bar() : f(std::shared_ptr<int>(new int), std::shared_ptr<int>(new int)) { } 
}; 

int main() { 
    bar b; 
} 

sẽ không được an toàn tuy nhiên kể từ khi tự đánh giá của các đối số của các nhà xây dựng của foo trong danh sách khởi tạo của bar là không xác định. Một trình biên dịch phù hợp có thể chọn để làm một chiều sâu hoặc chiều rộng thứ tự đầu tiên của đánh giá (hoặc bất cứ điều gì khác miễn là tất cả họ đã đánh giá một cách chính xác cuối cùng). Điều này có nghĩa là nếu new int thành công đầu tiên, nhưng cái thứ hai ném trước khi các đối tượng shared_ptr được xây dựng thì phân bổ đầu tiên được thực hiện vẫn có thể bị rò rỉ.

Nếu bạn thấy mình muốn thực hiện điều này, có hai giải pháp khả thi, ngoài việc quay trở lại xây dựng hai giai đoạn: đầu tiên có thể là một công cụ tái cấu trúc, thứ hai là xây dựng cá nhân đầu tiên của shared_ptr. , trước f. Điều nào là phù hợp nhất là một cuộc gọi phán xét mà tôi nghĩ cần phải được thực hiện trên cơ sở từng trường hợp.

5

Câu hỏi của tôi: là đoạn mã sau an toàn,

Vâng, đó sẽ là OK.

struct something { 
    something() 
     : p(new int(5)) 
    { } 

    std::unique_ptr<int> p; 
}; 

Lưu ý rằng mã ngây thơ

struct something { 
    something() 
     : p(new int(5)) 
    { } 

    int* p; 
}; 

sẽ được an toàn ngoại lệ, quá, bởi vì chỉ có một phân bổ có thể thất bại. Tôi nghĩ bạn đang nói thay vì về số

struct something { 
    something() 
     : p(new int(5)), q(new int) 
    { } 

    int *p, *q; 
}; 

điều đó sẽ không xảy ra. Con trỏ thông minh cũng sẽ hoạt động trong trường hợp đó.

+0

Ay, bạn hoàn toàn đúng; Tôi đã cập nhật ví dụ để thực sự kích hoạt rò rỉ. –

0

Bạn không cần xây dựng hai giai đoạn nếu bạn chỉ cần xử lý ngoại lệ. Đây là cách RIAA.

struct something { 
    something() 
     : p1(NULL) 
     , p2(NULL) 
    { 
     p1 = new int(2); 
     try { 
      p2 = new int(5); // May throw if allocation fails! 
     } catch (std::bad_alloc&) { 
      delete p1; //cleanup 
      throw; //rethrow 
     } 
    } 

    ~something() { 
     delete p1; 
     delete p2; 
    } 

    int* p1; 
    int* p2; 
}; 
+0

Nếu tôi không hoàn toàn nhầm lẫn, điều này rõ ràng là không ** theo cách RAII, bởi vì bạn đầu tiên ** khởi tạo ** 'p1' với' NULL', và ** sau đó phân bổ ** một 'int mới (2) '. – bitmask

+0

Điều này làm cho 'điều gì đó' thực hiện RAII, mặc dù nội bộ của nó không đáp ứng RIAA.Khi bạn đào sâu đủ vào nội bộ của bất kỳ lớp học RIAA, cuối cùng bạn _will_ có được một lớp học của những người nội bộ không thực hiện RIAA. Quan điểm của tôi là sự an toàn ngoại lệ và thiếu sự bắt đầu hai giai đoạn. 'unique_ptr' cũng không có thành viên RIAA. –

+0

Tôi hiểu. Lời xin lỗi của tôi. :) – bitmask

Các vấn đề liên quan