2010-06-06 26 views
6

Tôi đã tìm thấy một thực tế rất có hại về bản đồ stl. Đối với một số lý do tôi không thể nhận được các đối tượng được chèn vào bản đồ để xây dựng/hủy chỉ một lần.cách lấy bản đồ stl để xây dựng/hủy đối tượng được chèn chỉ một lần

Ví dụ:

struct MyObject{ 
    MyObject(){ 
     cout << "constructor" << endl; 
    } 
    ~MyObject(){ 
     cout << "destructor" << endl; 
    } 
}; 
int main() { 
    std::map<int, MyObject> myObjectsMap; 
    myObjectsMap[0] = MyObject(); 
    return 0; 
} 

lợi nhuận:

constructor 
destructor 
destructor 
constructor 
destructor 

Nếu tôi làm:

typedef std::pair<int, MyObject> MyObjectPair; 
myObjectsMap.insert(MyObjectPair(0,MyObject())); 

lợi nhuận:

constructor 
destructor 
destructor 
destructor 

Tôi đang chèn các đối tượng chịu trách nhiệm về việc cấp phát bộ nhớ của riêng mình, vì vậy khi bị phá hủy chúng sẽ tự làm sạch bản thân, bị phá hủy nhiều lần sẽ khiến tôi gặp rắc rối.

+1

rõ ràng, 'std :: map ' không cung cấp giao diện không sao chép để tạo mục nhập mới. Tôi khuyên bạn nên chia sẻ con trỏ ở đây - 'std :: map >' –

Trả lời

1

Đó là cách map và các vùng chứa khác hoạt động, bạn không thể thực hiện được. Đó là lý do tại sao std::auto_ptr không thể được sử dụng trong một bộ sưu tập, ví dụ.

+0

Tôi nghĩ mình sẽ chuyển sang vectơ và giữ con trỏ trên bản đồ. –

6

Tôi đề nghị bạn thêm một hàm tạo bản sao - đó là những gì đang được sử dụng cho các cấu trúc 'thiếu' tôi nghĩ.

Code:

#include <iostream> 
#include <map> 

using namespace std; 

struct MyObject{ 
    MyObject(){ 
     cout << "no-arg constructor" << endl; 
    } 
    MyObject(const MyObject&) { 
    cout << "const copy constructor" << endl; 
    } 
    ~MyObject(){ 
     cout << "destructor" << endl; 
    } 
}; 
int main() { 
    std::map<int, MyObject> myObjectsMap; 
    myObjectsMap[0] = MyObject(); 
    return 0; 
} 

Output:

no-arg constructor 
const copy constructor 
const copy constructor 
destructor 
destructor 
no-arg constructor 
destructor 
destructor 
4

std::map được phép làm như nhiều bản sao của các đối tượng của bạn vì nó muốn. Đây là việc thực hiện được xác định và bạn không có quyền kiểm soát điều này. Các cấu trúc "thiếu" bạn chú ý, bằng cách này, có thể là để gọi hàm tạo bản sao mà bạn không định nghĩa.

Những gì bạn có thể làm, tuy nhiên sử dụng trọng lượng để xây dựng một đối tượng trong thực tế tìm nạp đối tượng hiện có từ một nhóm các đối tượng đã tồn tại trước đó và hủy một đối tượng không làm gì cả. Các hồ bơi không bao giờ giải phóng các đối tượng của nó, nhưng nó luôn luôn duy trì một xử lý trên tất cả chúng. Bằng cách này, việc sử dụng bộ nhớ của bạn lớn từ khi bắt đầu dừng, nhưng nó không thay đổi nhiều trong suốt vòng đời của chương trình.

2

Để có thể sử dụng trong thùng chứa tiêu chuẩn, đối tượng của bạn phải có thể sao chép và gán được. Nếu đối tượng của bạn không phù hợp với điều này bạn có thể có vấn đề.

Điều đó nói rằng, nếu (như mẫu mã của bạn cho biết), bạn chỉ cần một đối tượng mặc định được xây dựng đưa vào bản đồ bạn chỉ có thể sử dụng toán tử [] cho tác dụng phụ của nó:

// Insert default constructed MyObject at key 0 
myObjectsMap[0]; 

Sửa

Tôi không rõ ràng về câu hỏi của bạn, nhưng nếu bạn không rõ về số đối tượng được xây dựng và tin rằng có một hàm tạo/hủy không khớp không khớp thì lưu ý rằng trình biên dịch sẽ cung cấp một hàm tạo bản sao không đăng nhập vào std::cout vì bạn không cung cấp một tuyên bố do người dùng khai báo.

+0

Tôi đã hy vọng có thể chỉ có một công trình và một sự hủy diệt, như thể tôi đang sử dụng một véc tơ. vector v; v.push_back (MyObject()); // chỉ tạo ra một công trình và hủy diệt. –

+0

Bạn đã thử nghiệm những gì 'myObjectsMap [0]; 'thực sự không? –

+0

Vâng, không thực sự, tôi đã thực sự sử dụng phương pháp chèn, nó có ít chi phí hơn nhưng vẫn tạo ra nhiều bản sao hơn tôi mong đợi. Dù bằng cách nào tôi nghĩ rằng tôi sẽ ở lại với véc tơ và sử dụng bản đồ chỉ cho con trỏ. Bài viết trên khá rõ ràng về những gì đang diễn ra. Tốt để biết. –

2

Khi bạn nói myObjectsMap [0], bạn đang gọi hàm tạo mặc định cho MyObject. Điều này là do không có gì trong [0] được nêu ra, và bạn chỉ cần truy cập nó. It's in the manual.

Khi bạn nhấn MyObject(); bạn đang tạo một cá thể MyObject tạm thời bằng cách sử dụng hàm tạo mặc định.

Vì bạn đã cho phép trình biên dịch xác định hàm tạo bản sao của bạn, bạn sẽ thấy nhiều hàm hủy hơn so với thông điệp của hàm tạo. (Có thể chỉ có một destructor, nhưng nhiều constructor, không giống như xây dựng một ngôi nhà.) Nếu bạn không bao giờ được sao chép đối tượng theo cách này, thì bạn có thể muốn khai báo private constructor sao chép và gán toán tử gán.

Bạn đang gọi constructor mặc định và các nhà xây dựng bản sao hai lần mỗi với mã này:

myObjectsMap[0] = MyObject(); 

Khi bạn làm điều này:

myObjectsMap.insert(MyObjectPair(0,MyObject())); 

bạn gọi constructor mặc định một lần và sao chép hàm tạo 3 lần.

Bạn có thể sử dụng con trỏ làm giá trị bản đồ thay cho chính đối tượng, đặc biệt tôi khuyên bạn nên xem shared_ptr.

note: tests were done using GCC 3.4.5 on a Windows NT 5.1 machine. 
Các vấn đề liên quan