2010-09-21 23 views
5

Tôi đến từ nền C# đến C++. Nói rằng tôi có một phương thức tạo một đối tượng trong một phương thức trên chồng, sau đó tôi chuyển nó sang phương thức lớp khác để thêm nó vào một vector của memeber.Tạo đối tượng trên ngăn xếp rồi chuyển qua tham chiếu đến phương thức khác trong C++

void DoStuff() 
{ 
    SimpleObj so = SimpleObj("Data", 4); 
    memobj.Add(so); 
} 

//In memobj 
void Add(SimpleObj& so) 
{ 
    memVec.push_back(so); //boost::ptr_vector object 
} 

Dưới đây là những câu hỏi của tôi:

  1. Khi các phương pháp DoStuff đầu sẽ như vậy đi ra khỏi phạm vi và được popped từ stack?
  2. memVec có con trỏ như vậy nhưng nó đã xuất hiện những gì xảy ra ở đây?
  3. Whats cách đúng để chuyển đối tượng ngăn xếp đến các phương thức lưu trữ chúng dưới dạng con trỏ?

Tôi nhận ra những điều này có thể hiển nhiên đối với một lập trình viên C++ với một số expereince.

Đánh dấu

+5

giống như một lưu ý phụ, "SimpleObj so = SimpleObj (" Dữ liệu ", 4);" không phải là rất C++ ish, sử dụng "SimpleObj như vậy (" Dữ liệu ", 4);" – Milan

+0

Cảm ơn, vẫn còn một số C# nôn nao .; – Mark

+0

@ milan1612: không may đó vẫn là ký hiệu di động nhất. một loạt các trình biên dịch C++ không thành công, [tương tự như trong trường hợp] (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.21). – Dummy00001

Trả lời

8
  1. Yes.
  2. Con trỏ vẫn "sống", nhưng trỏ đến một đối tượng không còn tồn tại. Điều này có nghĩa là lần đầu tiên bạn cố gắng dereference con trỏ như vậy bạn sẽ đi trong hành vi không xác định (có khả năng chương trình của bạn sẽ sụp đổ, hoặc, tệ hơn, sẽ tiếp tục chạy cho kết quả "lạ").
  3. Bạn chỉ đơn giản là không làm điều đó nếu bạn muốn giữ chúng sau khi hàm trả về. Đó là lý do tại sao phân bổ đống và vùng chứa lưu trữ bản sao đối tượng được sử dụng.

Cách đơn giản nhất để đạt được những gì bạn đang cố gắng làm sẽ được lưu trữ một bản sao của các đối tượng trong một container STL bình thường (ví dụ std::vector). Nếu các đối tượng đó nặng và tốn kém để sao chép xung quanh, bạn có thể muốn phân bổ chúng trên heap lưu trữ chúng trong một vùng chứa các con trỏ thông minh đầy đủ, ví dụ: boost::shared_ptr (xem ví dụ trong @Space_C0wb0y's answer).

Một khả năng khác là sử dụng boost::ptr_vector cùng với boost::ptr_vector_owner; lớp cuối cùng này sẽ chăm sóc "sở hữu" các đối tượng được lưu trữ trong liên kết ptr_vector và xóa tất cả các con trỏ khi nó nằm ngoài phạm vi. Để biết thêm thông tin về ptr_vectorptr_vector_owner, bạn có thể muốn xem this article.

+0

Cảm ơn, tôi muốn tránh sao chép các đối tượng xung quanh, nhưng cũng tránh phải quản lý bộ nhớ trên heap, vì vậy tôi nghĩ rằng tôi sẽ xem xét hai tùy chọn cuối cùng. – Mark

+0

Vì bạn đến từ C#, tôi khuyên bạn nên có một cái nhìn cũng tại các con trỏ thông minh khác được cung cấp bởi tăng và tìm hiểu nơi mà mỗi người trong số họ là tốt hơn được sử dụng. Quản lý bộ nhớ trong C++ không dễ dàng như trong C#, nhưng việc sử dụng con trỏ thông minh phù hợp sẽ trở nên gần như tự động. BTW, nếu câu trả lời của tôi hoặc câu trả lời khác giải quyết được vấn đề của bạn, bạn có thể xem xét đánh dấu nó là "được chấp nhận". –

+0

Vâng tôi đang sử dụng Boost lib, và con trỏ thông minh, chỉ không hiểu chúng đầy đủ, nhưng bạn đã khai sáng cho tôi, cảm ơn. – Mark

3

Để đạt được mục tiêu của bạn, bạn nên sử dụng một shared_ptr:

void DoStuff() 
{ 
    boost::shared_ptr<SimpleObj> so(new SimpleObj("Data", 4)); 
    memobj.Add(so); 
} 

//In memobj 
void Add(boost::shared_ptr<SimpleObj> so) 
{ 
    memVec.push_back(so); // std::vector<boost::shared_ptr<SimpleObj> > memVec; 
} 
+0

Ok điều đó có ý nghĩa, vì vậy số tham chiếu sẽ là một trên ptr một khi được thêm vào vectơ, sau đó nó sẽ không bị hủy. – Mark

+0

@Mark: Có. Và khi container bị phá hủy, số lượng tham chiếu cho mỗi 'shared_ptr' trong container sẽ bị giảm một (và các đối tượng sẽ bị xóa ngay tại chỗ nếu nó đạt 0). –

+0

Tôi muốn giới thiệu 'unique_ptr' thay cho' shared_ptr' nếu bạn đang sử dụng C++ 0x - có ít chi phí hơn. Thay vì tạo bản sao làm tăng số lượng tham chiếu, nó chỉ được di chuyển xung quanh. – AshleysBrain

0

Để lưu con trỏ vào đối tượng, đối tượng phải được tạo mới. Nếu không nó sẽ biến mất khi đi ra khỏi phạm vi.
Giải pháp dễ nhất cho vấn đề của bạn như được trình bày ở đây sẽ là sử dụng std :: vector thay vì tăng :: ptr_vector, vì cách này push_back sẽ sao chép đối tượng trong vector

1

Có đối tượng của bạn sẽ bị xuất hiện ngăn xếp khi chức năng của bạn rời khỏi phạm vi. Bạn nên tạo một đối tượng heap bằng cách sử dụng new và thêm một con trỏ vào đối tượng đó trong vectơ của bạn.

Như đã nói trước đây, con trỏ trong vector của bạn sẽ trỏ đến một cái gì đó không xác định lần đầu tiên chức năng của bạn đi ra khỏi phạm vi

1

Đó mã sẽ không biên dịch bởi vì bên trong hàm Add bạn đang cố gắng để cố gắng đẩy một toàn bộ đối tượng vào một vectơ mà mong đợi một con trỏ đến một đối tượng.

Nếu thay vào đó bạn lấy địa chỉ của đối tượng đó và đẩy nó lên vectơ, thì sẽ rất nguy hiểm vì đối tượng ban đầu sẽ bị chặn khỏi ngăn xếp và con trỏ bạn đã lưu sẽ trỏ tới bộ nhớ chưa được khởi tạo.

Nếu bạn đang sử dụng một véc tơ bình thường thay vì một vector con trỏ thì cuộc gọi push_back sẽ sao chép toàn bộ đối tượng thay vì con trỏ và do đó nó sẽ an toàn. Tuy nhiên, điều này không nhất thiết phải hiệu quả, và cách tiếp cận 'sao chép mọi thứ' có lẽ không trực quan với ai đó từ thế giới C#, Java hoặc Python.

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