cách 2 gần với Java hơn, đúng hơn là giống hệt Java. Trong Java bất kì object nào cũng nằm trên heap, tức là cấp phát động trường hợp 2, trừ các kiểu nguyên thủy là nằm trên stack. Nếu bạn khởi tạo 1 biến trên Java = new T(…) tức là nó nằm trên heap rồi đó. Java nó chỉ hạn chế ko cho sử dụng pointer arithmetic (cộng trừ pointer) rồi gọi pointer là “reference”.
Java khác với C++ ở chỗ Java có người thu dọn dùm, gọi là garbage collector, người thu dọn rác. C++ object nào cấp phát động cái gì phải tự thu dọn cái đó, nhưng có destructor thì mình ko cần tự thu dọn mà để object tự dọn. Nếu con trỏ/reference trong Java có GC lo thì con trỏ trong C++ sẽ được viết lại thành 1 class để có destructor lo. Vì vậy viết code C++11 thì tuyệt đối ko xài new/delete hay raw pointer mà phải xài unique_ptr, shared_ptr. Ví dụ
class Person
{
public:
Person(int id, const std::string& name) : id(id), name(name) {}
private:
int id;
std::string name;
};
...
Person john(101, "John"); //john nằm trên stack
//Person* pAlice = new Person(102, "Alice"); //ko viết như vậy nữa
auto pAlice = std::make_shared<Person>(102, "Alice"); //nên viết như vậy, ko sợ leak memory
unique_ptr lẹ hơn shared_ptr nhưng cách xài phức tạp hơn. Ngoài ra còn có weak_ptr để tránh liên kết vòng bằng shared_ptr. Phức tạp hơn con trỏ thông thường nhiều nên người ta ít xài mặc dù nếu xài thì chả phải lo leak memory nữa.