2013-03-01 34 views
5

Tôi có một danh sách std::list<T *> *l;. danh sách này không phải là null và có một số giá trị. Vấn đề của tôi là cách truy cập các mục đúng cách? tôi không cần phải lặp qua danh sách. tôi chỉ muốn mục đầu tiên thôi.Làm cách nào để truy cập phần tử std :: list đầu tiên?

std::list<T*>::iterator it = l->begin(); 

if (it != l->end()) 
{ 
    // accessing T 
    int value = (*it)->value(); // Is this safe? 
} 

hoặc tôi có nên kiểm tra giá trị không?

if (it != l->end() && (*it)) 
{ 
    // accessing T 
    int value = (*it)->value(); 
} 
+0

Bạn đang giữ con trỏ, vì vậy hãy kiểm tra 'NULL'. Hoặc sử dụng một 'std :: list '. – juanchopanza

+3

Điều gì khiến bạn quyết định sử dụng 'std :: list ' thay vì 'std :: list '? – LihO

+0

Có thực sự cần thiết để sử dụng các con trỏ thô không? ... –

Trả lời

8

Nếu bạn buộc phải sử dụng std::list<T*> myList; và giả sử rằng T được định nghĩa là:

struct T 
{ 
    T(const char* cstr) : str(cstr){ } 
    std::string str; 
}; 

sau đó chỉ cần sử dụng std::list::front để truy cập phần tử đầu tiên:

std::string firstStr = myList.front()->str; 

Lưu ý rằng trong trường hợp này myList.front() lợi nhuận tham chiếu đến phần tử đầu tiên trong danh sách của bạn, tham chiếu đến con trỏ trong trường hợp này. Vì vậy, bạn có thể xử lý nó giống như một con trỏ đến phần tử đầu tiên.

Và câu hỏi của bạn về NULL: Khi bạn làm việc với vùng chứa con trỏ, con trỏ sẽ bị xóa khỏi vùng chứa khi đối tượng bị hủy. Khi bạn bắt đầu sử dụng con trỏ, điều này thường có nghĩa là bạn là người chịu trách nhiệm quản lý bộ nhớ được kết nối với các đối tượng mà các con trỏ trỏ tới (đó là lý do chính tại sao bạn nên thích std::list<T> hơn std::list<T*> luôn khi có thể).

Thậm chí tồi tệ hơn NULL con trỏ là con trỏ tòn ten: Khi bạn tạo một đối tượng, lưu trữ địa chỉ của nó trong bao bì của bạn, nhưng bạn sẽ không loại bỏ địa chỉ này từ container của bạn một khi đối tượng là destructed, sau đó con trỏ này sẽ trở thành không hợp lệ và cố gắng truy cập vào bộ nhớ mà con trỏ trỏ tới sẽ tạo ra hành vi không xác định. Vì vậy, không chỉ bạn nên đảm bảo rằng std::list của bạn không chứa các con trỏ NULL, bạn cũng nên đảm bảo rằng nó chỉ chứa các con trỏ tới các đối tượng hợp lệ vẫn tồn tại.

Vì vậy, theo thời gian, bạn sẽ được dọn dẹp những yếu tố này, bạn sẽ thấy mình bỏ con trỏ ra khỏi danh sách của bạn và xóa đối tượng họ trỏ đến cùng một lúc:

std::list<T*> myList; 

myList.push_back(new T("one")); 
myList.push_back(new T("two")); 
myList.push_back(new T("three")); 
myList.push_back(new T("four")); 

while (!myList.empty()) 
{ 
    T* pT = myList.front();      // retrieve the first element 
    myList.erase(myList.begin());    // remove it from my list 
    std::cout << pT->str.c_str() << std::endl; // print its member 
    delete pT;         // delete the object it points to 
} 

Nó cũng đáng để đọc những câu hỏi sau:
Can you remove elements from a std::list while iterating through it?
Doesn't erasing std::list::iterator invalidates the iterator and destroys the object?

+0

isnt .front() một hàm đã xóa hiện tại? nếu như vậy những gì để sử dụng thay thế? – serup

0

Sự cần thiết phải kiểm tra null yếu tố danh sách phụ thuộc hoàn toàn vào những gì có thể được đưa vào danh sách ngay từ đầu.

Nếu có thể danh sách chứa con trỏ rỗng, thì bạn chắc chắn nhất nên kiểm tra NULL trước khi truy cập phần tử.
Nếu không thể, thì cũng không có lý do gì để kiểm tra.

+0

Tôi không đồng ý, bạn nên luôn luôn kiểm tra NULL, đặc biệt là trong DEBUG/xây dựng phát triển. Nếu nó không giả sử là NULL, hãy ném một ngoại lệ. –

+0

@AlexChamberlain: Trong trường hợp đó, tại sao cũng không kiểm tra xem con trỏ vẫn đề cập đến một đối tượng sống hợp lệ? –

+0

Nếu tôi có thể nghĩ ra một cách, tôi sẽ xây dựng DEBUG. –

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