2011-09-27 18 views
9

Giả sử tôi có:C++: Tôi có nên khởi tạo thành viên con trỏ được chỉ định trong phần thân hàm tạo thành NULL không?

// MyClass.h 
class MyClass 
{ 
    public: 
    MyClass(); 

    private: 
    Something *something_; 
} 

// MyClass.cpp 
MyClass::MyClass() 
{ 
    something_ = new Something(); 
} 

Tôi có nên khởi something_ để NULL (hoặc 0) trong các nhà xây dựng danh sách khởi tạo của các nhà xây dựng MyClass? Hay điều đó là không cần thiết bởi vì tôi đang gán cho nó trong phần thân của nhà xây dựng? Thực hành được khuyến nghị là gì?

+8

Tại sao không chỉ khởi tạo con trỏ ở nơi đầu tiên? 'MyClass :: MyClass(): something_ (new Something())' –

+0

Ồ, đó có phải là phương pháp hay nhất không? – User

+3

Luôn thích khởi tạo nhiệm vụ trong phần thân của hàm tạo. Và sử dụng một con trỏ thông minh như 'shared_ptr' hoặc' scoped_ptr' thay vì một con trỏ riêng để dọn dẹp tự động, ngay cả trong trường hợp ngoại lệ. –

Trả lời

11

Nói chung, bạn chỉ gán nó một lần, trong danh sách khởi tạo hoặc cơ thể, trừ khi khởi tạo cơ thể có thể hoặc không thể xảy ra, hoặc có mã điều kiện tiên quyết:

MyClass::MyClass() 
{ 
    //this code must happen first 
    // _now_ max is known 
    something_ = new Something(max); 
} 

MyClass::MyClass() 
{ 
    if (max) 
     something_ = new Something(max); 
    else 
     something_ = NULL; 
} 

MyClass::MyClass() 
    : something_(new Something()) 
//as pointed out in the comments, use smart pointers 
{ 
} 
+5

Khởi tạo thành viên dữ liệu con trỏ với kết quả phân bổ động _trong danh sách khởi tạo_ là một ý tưởng tồi. Quá nhiều thứ có thể sai. Ví dụ, nếu một ngoại lệ được ném trong khi xây dựng một số thành viên dữ liệu khác, làm thế nào để bạn biết các thành viên dữ liệu nào được khởi tạo để bạn có thể hủy bỏ đối tượng được cấp phát động? Ngay cả khi bạn sử dụng khối chức năng thử, bạn không biết việc xây dựng thất bại ở đâu. (Tất nhiên, người ta nên sử dụng một con trỏ thông minh, trong trường hợp phân bổ động trong trường hợp danh sách khởi tạo là okay, nhưng hãy cẩn thận khi sử dụng con trỏ bình thường). –

+1

@James: Tất nhiên, người ta nên sử dụng một con trỏ thông minh thay vì một con trỏ tự nhiên. (Hah, bạn chỉ cần chỉnh sửa bình luận của bạn để nói điều đó.) –

+0

Nếu tôi đang tạo ra các đối tượng khác nhau và cái đầu tiên yêu cầu thứ hai là đối số? Bạn có thể sử dụng trình khởi tạo trong trường hợp này hay nó giống như ví dụ tối đa của bạn? (ví dụ: ': something_ (new Something()), somethingElse_ (new SomethingElse (cái gì đó _)) ...') – User

2

Nói chung - không. Nhưng nếu một nơi nào đó trong con trỏ constructor của bạn được sử dụng trước khi nó được khởi tạo thì bạn sẽ nhận được hành vi không xác định. Tuy nhiên, vấn đề lớn nhất mà bạn có là điều này - nếu ngoại lệ được ném vào hàm tạo, hàm hủy của nó không được gọi. Vì vậy, hãy tưởng tượng bạn có hai con trỏ đến các đối tượng và phân bổ đối tượng đầu tiên thành công trong khi phân bổ thứ hai không thành công, trong trường hợp đó bạn kết thúc với một rò rỉ tài nguyên. Điều này có thể được giải quyết bằng cách sử dụng con trỏ "thông minh". Nhưng trong trường hợp đó, chúng sẽ được khởi tạo trong danh sách khởi tạo, và nếu bạn không muốn gán giá trị cho chúng hai lần thì bạn nên cấp phát bộ nhớ trong đó hơn là trong phần thân của hàm tạo.

+0

Tôi không nghĩ đến vấn đề an toàn ngoại lệ tiềm ẩn. –

1

Không cần thiết, đặc biệt là nếu bạn ngay lập tức khởi tạo trong các nhà xây dựng cơ thể, tuy nhiên nếu khởi tạo không phải là quá rõ ràng thì tại sao không NULL nó để tránh tình cờ truy cập vào biến uninitialized.

  • tối thiểu trên không hiệu quả
  • tiết kiệm rất nhiều thời gian gỡ lỗi/xử lý sự cố với săn lỗi điên
+0

* 'săn mồi điên '* - chắc chắn. Bây giờ tôi đang tìm kiếm một sự rò rỉ tài nguyên (một đối tượng người dùng Windows), và rắc rối nhất làm cho các cuộc gọi 'mới' trong danh sách khởi tạo: không có trước/sau trong thế giới" nguyên tử "của các danh sách khởi tạo. – Wolf

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