2012-05-09 41 views
5

Tôi có một hàm trả về một trình lặp nếu một đối tượng được tìm thấy.trả về C++ iterators

Bây giờ tôi gặp sự cố. Làm cách nào để khắc phục sự cố thông báo đối tượng gọi là hàm này mà đối tượng không được tìm thấy?

vector<obj>::iterator Find(int id, int test) 
{ 
     vector<obj>::iterator it; 
      aClass class; 

      for(it = class.vecCont.begin(); it != class.vecCont.end(); ++it) 
      { 
       if(found object) //currently in psuedo code 
       return it; 
      } 

      return ???? // <<< if not found what to insert here? 

} 

Tôi có cần phải thay đổi cấu trúc dữ liệu của mình thay thế không?

Cảm ơn trước! :)

+2

Nếu bạn không có lý do cụ thể để sử dụng của riêng bạn, hãy xem xét 'std :: find'. Cách nó được thực hiện mặc dù, là nó sẽ trả về 'end()'. – chris

+2

Điều này có vẻ giống như một lỗ hổng thiết kế. Trả về một bản sao, một con trỏ, một bool cho biết trạng thái tìm thấy và sửa đổi một cá thể đầu vào thông qua tham chiếu, nhưng KHÔNG trả về một trình lặp cho một container ẩn! –

+0

tìm thấy độ phức tạp là O (n). tôi đang thực sự sử dụng một tìm kiếm nhị phân kết thúc trở lại để thực hiện tìm kiếm. Điều này quan trọng khi im triển khai một hệ thống phân tán rất lớn. – mister

Trả lời

0

Không trả lại trình lặp cho vùng chứa ẩn. Quay trở lại chỉ đơn giản là những gì nó là bạn muốn, cụ thể là một phương tiện để truy cập vào một đối tượng nếu nó tồn tại. Trong ví dụ này, tôi lưu trữ các đối tượng trong vùng chứa thông qua con trỏ.Nếu đối tượng của bạn chỉ tồn tại tạm thời, sau đó mới lên và sao chép đối tượng trên!

class AClass; 

//...some time later 
std::vector<AClass*> vecCont; //notice, store pointers in this example! 

//..some time later 
AClass * findAClass(int id, int test) 
{ 
    vector<AClass*>::iterator it; 

    for(it = class.vecCont.begin(); it != class.vecCont.end(); ++it) 
    { 
    if(found object) //currently in psuedo code 
    return it; 
    } 

    return NULL; 
} 

//later still.. 

AClass *foundVal = findAClass(1, 0); 
if(foundVal) 
{ 
    //we found it! 
} 
else 
{ 
    //we didn't find it 
} 

chỉnh sửa: điều thông minh cần làm là viết bộ so sánh cho lớp của bạn và sử dụng thuật toán std sắp xếp và tìm chúng cho bạn. Tuy nhiên, hãy làm những gì bạn muốn.

+0

Tôi muốn điều này nếu bạn đã đề nghị sử dụng con trỏ chia sẻ. Giới thiệu con trỏ thô ở đây làm tổn thương cảm xúc của tôi. –

+0

Trải nghiệm của tôi với các con trỏ chia sẻ/thông minh không được tốt nói chung. Nó tìm mã được phân lập bên trong các lớp của riêng bạn, nhưng điều xảy ra với tôi (ít nhất là trên các dự án của tôi) là tôi gặp phải vấn đề khi giao diện mã cần giao tiếp với nhau và cần một con trỏ thô. Ngoài ra, bạn cầu xin cho các đối tượng sống lâu hơn họ nên hoặc người nào khác trong các tiểu bang không nhất quán vì thứ tự hủy diệt không dễ kiểm soát. Tôi tìm thấy nó đơn giản hơn để chỉ đóng gói con trỏ và làm cho nó được biết đến "đây là của tôi. Bạn chỉ mượn nó. Đừng lưu trữ nó. Hãy xin phép tôi trước khi sử dụng nó." –

+0

Đừng bỏ cuộc! Ví dụ của bạn giống như một công việc cho [std :: weak_ptr] (http://en.cppreference.com/w/cpp/memory/weak_ptr). Theo ý kiến ​​của tôi, sử dụng con trỏ thông minh thuộc bất kỳ loại nào gần như luôn luôn là con đường để đi - hãy nghĩ đến sự an toàn ngoại lệ ([RAII] (http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization)) cho một. Tôi đồng ý rằng khi giao dịch với các giao diện, bạn có thể nhận được hosed, đặc biệt là nếu các giao diện là một sản phẩm/API và bạn không có kiểm soát. Nhưng nó vẫn đáng giá đối với tôi. –

5

Bạn có thể trả về một trình lặp đến cuối, tức là return class.vecCont.end() để cho biết điều đó.

7

Return vector::end(), ném một ngoại lệ, hoặc trả lại một cái gì đó khác hơn là một iterator đồng bằng

Hơn thế nữa, không thực hiện Find chức năng của riêng bạn. Đó là thư viện <algorithm> dành cho. Dựa trên mã psudocode của bạn, bạn có thể sử dụng std::find hoặc std::find_if. find_if đặc biệt hữu ích trong trường hợp bình đẳng không nhất thiết có nghĩa là operator==. Trong những trường hợp đó, bạn có thể sử dụng lambda [C++ 11] hoặc nếu C++ 11 không có sẵn cho bạn, một lớp functor.

Kể từ khi functor là mẫu số chung thấp nhất, tôi sẽ bắt đầu với điều đó:

#include <cstdlib> 
#include <string> 
#include <algorithm> 
#include <vector> 
#include <functional> 
using namespace std; 

class Person 
{ 
public: 
    Person(const string& name, unsigned age) : name_(name), age_(age) {}; 

    string name_; 
    unsigned age_; 
}; 

class match_name : public unary_function <bool, string> 
{ 
public: 
    match_name(const string& rhs) : name_(rhs) {}; 
    bool operator()(const Person& rhs) const 
    { 
    return rhs.name_ == name_; 
    } 
private: 
    string name_; 
}; 

#include <iostream> 

int main() 
{ 
    vector<Person> people; 
    people.push_back(Person("Hellen Keller", 99)); 
    people.push_back(Person("John Doe", 42)); 

    /** C++03 **/ 
    vector<Person>::const_iterator found_person = std::find_if(people.begin(), people.end(), match_name("John Doe")); 

    if(found_person == people.end()) 
     cout << "Not FOund"; 
    else 
     cout << found_person->name_ << " is " << found_person->age_; 
} 

found_person nay chỉ vào người có tên là "John Doe", nếu không chỉ ra people_.end() nếu người đó wasn Không tìm thấy.

Một lambda C++ 11 là cú pháp ngôn ngữ mới làm cho quá trình khai báo/định nghĩa một hàm và sử dụng đơn giản hơn trong nhiều trường hợp. Nó được thực hiện như thế này:

string target = "John Doe"; 
vector<Person>::const_iterator found_person = std::find_if(people.begin(), people.end(), [&target](const Person& test) { return it->name_ == target; }); 
+0

Tôi nghĩ rằng một ngoại lệ thực sự là sự lựa chọn đúng nếu một iterator là không thể. (Ví dụ vì người gọi không biết rằng nó nên so sánh với kết thúc() hoặc nếu điều này chỉ đơn giản là không hiển thị cho người gọi.) – TaZ

1

Bạn nên trả lại class.vecCont.end() nếu đối tượng không được tìm thấy. Nhưng @chris là đúng - đây chính xác là những gì std::find là dành cho.

2

Làm thế nào về việc chỉ trả về trình lặp kết thúc?

Mã của bạn trở thành: -

vector<obj>::iterator Find(int id, int test) 
{ 
    vector<obj>::iterator it; 
    aClass class; 

    for(it = class.vecCont.begin(); it != class.vecCont.end(); ++it) 
    { 
    if(found object) //currently in psuedo code 
     break; 
    } 

    return it; 
} 

hoặc chỉ sử dụng std::find.

1

Something như thế này

std::vector<obj>::iterator pos; 
pos = find(coll.begin(),coll.end(), val); 

Và đừng quên những kiểm tra cho sự hiện diện của nguyên tố của bạn hay không trong container

if (pos != coll.end()) 
0

Không bao giờ bắt chước std::algorithm chức năng bên trong một lớp. Chúng là các hàm miễn phí vì một lý do. Nó thường là đủ để lộ beginend chức năng thành viên trả về trình vòng lặp bên phải (và có thể là boost::iterator_range). Nếu bạn cần làm một tìm kiếm ưa thích với một functor, phơi bày functor là tốt.