Nó tinh tế hơn những câu trả lời khác cho thấy. Không có sự phân chia tuyệt đối giữa dữ liệu trên ngăn xếp và dữ liệu trên heap dựa trên cách bạn khai báo nó. Ví dụ:
std::vector<int> v(10);
Trong phần thân của hàm, khai báo một vector
(mảng động) gồm mười số nguyên trên ngăn xếp. Nhưng lưu trữ được quản lý bởi vector
không phải trên ngăn xếp.
À, nhưng (các câu trả lời khác cho thấy) thời gian lưu trữ bị giới hạn bởi thời gian tồn tại của vector
chính nó, ở đây là dựa trên ngăn xếp, vì vậy nó không có gì khác biệt khi thực hiện - chúng ta chỉ có thể coi nó là một đối tượng dựa trên ngăn xếp với giá trị ngữ nghĩa.
Không phải vậy. Giả sử hàm là:
void GetSomeNumbers(std::vector<int> &result)
{
std::vector<int> v(10);
// fill v with numbers
result.swap(v);
}
Vì vậy, bất cứ thứ gì có swap
hàm (và bất kỳ loại giá trị phức tạp nào cũng cần có) đều có thể đóng vai trò là một loại tham chiếu có thể đảo ngược đối với một số dữ liệu heap, trong một hệ thống đảm bảo một chủ sở hữu duy nhất của dữ liệu đó.
Do đó, cách tiếp cận C ++ hiện đại là không bao giờ lưu trữ địa chỉ của dữ liệu heap trong các biến con trỏ cục bộ. Tất cả các phân bổ heap phải được ẩn trong các lớp.
Nếu bạn làm điều đó, bạn có thể nghĩ về tất cả các biến trong chương trình của mình như thể chúng là các loại giá trị đơn giản và quên hoàn toàn heap (ngoại trừ khi viết một lớp bao bọc giống như giá trị mới cho một số dữ liệu heap, điều này không bình thường) .
Bạn chỉ cần giữ lại một chút kiến thức đặc biệt để giúp bạn tối ưu hóa: khi có thể, thay vì gán một biến cho một biến khác như thế này:
a = b;
trao đổi chúng như thế này:
a.swap(b);
bởi vì nó nhanh hơn nhiều và nó không ném ngoại lệ. Yêu cầu duy nhất là bạn không cần b
tiếp tục giữ cùng một giá trị ( a
thay vào đó sẽ nhận được giá trị thay vào đó, sẽ được chuyển vào a = b
).
Nhược điểm là cách tiếp cận này buộc bạn phải trả về giá trị từ các hàm thông qua các tham số đầu ra thay vì giá trị trả về thực tế. Nhưng họ đang sửa nó trong C ++ 0x với các tham chiếu rvalue .
Trong những tình huống phức tạp nhất, bạn sẽ đưa ý tưởng này đến mức cực đoan chung và sử dụng một lớp con trỏ thông minh như shared_ptr
đã có trong tr1. (Mặc dù tôi cho rằng nếu bạn có vẻ cần nó, bạn có thể đã di chuyển ra ngoài điểm áp dụng ngọt ngào của Standard C ++.)