2010-07-10 37 views
8

Chính sách tốt khi sử dụng "mới" để tạo một phiên bản của một lớp học là gì? Tôi đã sở thích lập trình C++ cho một thời gian nhưng tôi vẫn không chắc chắn khi nào là thời gian tốt nhất để làm điều này:khi nào sử dụng mới trong C++?

MyClass thing(param1, param2); 

trên này:

MyClass* thing; 
thing = new MyClass(param1, param2); 

Bất cứ lời khuyên?

+0

Có. Lời khuyên của tôi là đọc cuốn sách này: http://www2.research.att.com/~bs/3rd.html đặc biệt là chương 5: Con trỏ, Mảng và Cấu trúc –

+2

Bạn có hiểu tại sao bạn có thể cần để tạo các đối tượng động? –

Trả lời

0
MyClass thing(param1, param2); //memory for thing is allocated on the process stack(static allocation) 

MyClass* thing; 
thing = new MyClass(param1, param2); //memory is allocated dynamically on the heap(free store) for thing 

Sự khác biệt nằm ở đây:

int main() 
{ 
    { 
    MyClass thing(param1, param2); //thing is local to the scope 
    } //destructor called for thing 
    //cannot access thing (thing doesn't exist) 
} 

int main() 
{ 
    { 
    MyClass* thing; 
    thing = new MyClass(param1, param2); 
    } 
    //the object pointed to by thing still exists 
    //Memory leak 
} 

Đối với các đối tượng lớn bạn phải cấp phát bộ nhớ động (sử dụng mới) vì quá trình ngăn xếp có kích thước hạn chế.

+0

Vâng, bạn vẫn không thể truy cập 'điều' sau khi phạm vi kết thúc. :) Nó vẫn tồn tại mặc dù, và vì không còn bất kỳ con trỏ trỏ đến nó, nó không bao giờ có thể được phát hành. – GManNickG

+0

@GMan: Vâng, bạn nói đúng. Bài đăng của tôi yêu cầu một số chỉnh sửa nhỏ. –

+1

'điều' MyClass * sẽ không còn tồn tại ở nơi bạn xác nhận quyền sở hữu, vì đó là biến cục bộ nằm ngoài phạm vi. Đối tượng MyClass - mà 'điều' được sử dụng để trỏ tới - sẽ tiếp tục tồn tại và đối tượng này là nguyên nhân gây rò rỉ bộ nhớ. –

2

Quy tắc chung là: nếu nó hoạt động mà không cần new, không sử dụng new.

+3

Đó là một ý tưởng tồi. Nó có vẻ hoạt động khi bạn truyền con trỏ xung quanh, cho đến khi khung ngăn xếp được giải phóng. Thế thì bỗng nhiên bạn có tham chiếu đến hư vô. Gỡ lỗi là đủ cứng mà không cần thêm mã thử và lỗi vào hỗn hợp. – Borealid

+0

Nhưng không có con trỏ nào liên quan đến 'điều MyClass (param1, param2);'. Nếu bạn có thể sử dụng các đối tượng như bạn sử dụng một 'int', bạn nên. –

+3

nếu ai đó không biết sự khác biệt giữa ngăn xếp và đống (như hiển nhiên bởi câu hỏi) bắt đầu 'mã hóa bằng thử và lỗi', anh ta buộc phải tìm ra rằng anh ta có thể trả về '& myStackobj', và dường như nó hoạt động '. – Javier

5

Cách tiếp cận đầu tiên tạo một cá thể cục bộ trên ngăn xếp biến mất khi chức năng gọi thoát. Thứ hai tạo một cá thể nằm trên heap cho đến khi (và nếu) bạn giải phóng nó một lần nữa. Sự lựa chọn phụ thuộc vào loại điều khiển và tuổi thọ bạn muốn cho đối tượng của mình.

2

Nói chung: bạn không cần sử dụng new nếu bạn định xóa đối tượng trong cùng một phạm vi. Nếu đối tượng là khá lớn, bạn có thể muốn sử dụng new.
Bạn có thể muốn xem xét sự khác biệt giữa bộ nhớ heap và ngăn xếp nếu bạn muốn biết chi tiết.

22

Thiết kế khôn ngoan, sử dụng phân bổ tự động (stack) nhiều nhất có thể. Bất cứ khi nào bạn cần kéo dài thời gian tồn tại của một đối tượng vượt ra ngoài phạm vi nhất định, sau đó phân bổ động nó.

Và thậm chí như vậy, không bao giờ tự động phân bổ mọi thứ raw. Luôn luôn giữ chúng được bao bọc trong một số loại wrapper thực hiện Quản lý tài nguyên phạm vi (SBRM, đầu tiên được biết đến dưới tên ngu ngốc/vụng về là Resource-Acquisition Is Initialization hoặc RAII.) Đó là phân bổ động nên được giữ trong các đối tượng tự động sẽ làm sạch lên tự động!

Một ví dụ điển hình là std::vector: bạn không thể làm rò bộ nhớ bên trong thành vector, bởi vì trình phá hủy được chạy trong mọi trường hợp khi bộ nhớ được giải phóng và nó sẽ giải phóng nó cho bạn. auto_ptr là con trỏ thông minh đầu tiên và duy nhất có sẵn trong thư viện chuẩn, nhưng nó khá tệ. Tốt hơn là sử dụng shared_ptr hoặc nhiều con trỏ thông minh phổ biến khác có sẵn trong Boost và/hoặc TR1 và/hoặc C++ 0x.

Hiệu suất khôn ngoan, đối tượng được phân bổ trên ngăn xếp có thể được thực hiện nhanh chóng Ngược lại, phân bổ động thường đòi hỏi nhiều thời gian hơn. Nó hoàn toàn có thể để có được phân bổ động nhanh chóng với các lược đồ phân bổ tùy chỉnh, nhưng thậm chí tốt nhất vẫn sẽ chậm hơn so với phân bổ stack.

Thỉnh thoảng, bạn có thể thấy bạn dành quá nhiều thời gian sao chép các đối tượng xung quanh. Trong trường hợp này, có thể đáng để phân bổ động nó và chỉ di chuyển con trỏ xung quanh. Tuy nhiên, xin lưu ý tôi đã nói "tìm". Loại thay đổi này là thứ bạn tìm thấy bằng cách định hình và đo lường, không bao giờ đoán được.

Vì vậy: Phân bổ tự động khi có thể, phân bổ động khi cần.

+2

+1 cho câu trả lời giả định :-) –

+2

+1 cho "chỉ khi cần thiết" – rubenvb

+2

+1 đặc biệt là để gọi RAII một tên ngớ ngẩn và vụng về, đó là gì. – Dan

1

Trước tiên, hãy tự hỏi mình câu hỏi, liệu đối tượng có được sao chép khi một chức năng khác muốn sao chép nó có ý nghĩa không?

Nếu có ý nghĩa khi sao chép đối tượng, đặt cược tốt nhất của bạn là tạo mọi thứ trên ngăn xếp hoặc dưới dạng biến thành viên và sau đó chỉ chuyển các bản sao xung quanh khi cần.

Nếu không sao chép đối tượng, bạn cần sử dụng biểu mẫu new để bạn có thể chuyển con trỏ đến đối tượng một cách an toàn. Bạn phải sử dụng một con trỏ (hoặc tham chiếu) vì như đã lưu ý nó không có ý nghĩa để sao chép đối tượng.

Có hai ngoại lệ Tôi nhận thức được:

Nếu bạn biết đối tượng sẽ không được sử dụng sau khi các chức năng hiện tại kết thúc, bạn có thể tạo ra các đối tượng trên stack để nó bị xóa . Chỉ cần thực hiện rất chắc chắn không ai giữ trên một con trỏ đến nó sau đó! (Tôi hiếm khi thấy trường hợp này xảy ra), nhưng điều đó xảy ra)

Nếu đối tượng được sử dụng trong nội bộ bởi một lớp khác không được sao chép xung quanh, bạn có thể đặt nó làm biến thành viên. Vì đối tượng trong đó sẽ không được sao chép, và chỉ đối tượng của nó để sử dụng nội bộ sẽ an toàn.

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