2012-03-01 29 views
12

Vì vậy, tôi đã có vấn đề với std :: map, lambda và stl algorithm (remove_if). Trên thực tế, cùng một mã với std :: list hoặc std :: vector hoạt động tốt.bản đồ, lambda, remove_if

kiểm tra ví dụ của tôi: nhắn

#include <map> 
#include <iostream> 
#include <algorithm> 

struct Foo 
{ 
    Foo() : _id(0) {} 
    Foo(int id) : _id(id) 
    { 

    } 

    int _id;  
}; 
typedef std::map<int, Foo> FooMap; 


int main() 
{ 
    FooMap m; 
    for (int i = 0; i < 10; ++i) 
     m[i + 100] = Foo(i); 

    int removeId = 6; 
    // <<< Error here >>> 
    std::remove_if(m.begin(), m.end(), [=](const FooMap::value_type & item) { return item.second._id == removeId ;}); 

    for (auto & item : m) 
     std::cout << item.first << " = " << item.second._id << "\n";  

    return 0; 
} 

Lỗi:

In file included from /usr/include/c++/4.6/utility:71:0, 
       from /usr/include/c++/4.6/algorithm:61, 
       from main.cxx:1: 
/usr/include/c++/4.6/bits/stl_pair.h: In member function ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1, _T2>&&) [with _T1 = const int, _T2 = Foo, std::pair<_T1, _T2> = std::pair<const int, Foo>]’: 
/usr/include/c++/4.6/bits/stl_algo.h:1149:13: instantiated from ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::_Rb_tree_iterator<std::pair<const int, Foo> >, _Predicate = main()::<lambda(const value_type&)>]’ 
main.cxx:33:114: instantiated from here 
/usr/include/c++/4.6/bits/stl_pair.h:156:2: error: assignment of read-only member ‘std::pair<const int, Foo>::first’ 

Tôi không hiểu có chuyện gì đây. Vì vậy, tôi sẵn sàng đọc một số lời khuyên/hướng dẫn về nó. Mục tiêu của tôi - sử dụng kiểu lambda mới với std :: map và các thuật toán, chẳng hạn như remove_if.

g ++ 4.6, -std = C++ 0x.

+2

'remove_if' chấp nhận một cặp vòng lặp và trả về trình lặp. Bạn nghĩ nó sẽ loại bỏ các phần tử ** từ đâu **? –

Trả lời

27

Vấn đề là std::map<K,V>::value_typestd::pair<const K, V>, còn gọi là .firstconst và không thể chuyển nhượng được. Lambdas không liên quan gì đến vấn đề ở đây.

std::remove_if "xóa" các mục bằng cách di chuyển các phần tử của vùng chứa xung quanh, sao cho mọi thứ không vừa với biến vị ngữ ở phía trước, trước trình lặp lặp lại. Mọi thứ sau trình lặp đó không được chỉ định. Nó làm điều đó với nhiệm vụ đơn giản, và vì bạn không thể gán cho biến số const, bạn nhận được lỗi đó.

Tên remove có thể gây nhầm lẫn một chút và trong trường hợp này, bạn thực sự muốn erase_if, nhưng than ôi, không tồn tại. Bạn sẽ phải làm gì với iterating trên tất cả các mục và xóa chúng bằng tay với map.erase(iterator):

for(auto it = map.begin(), ite = map.end(); it != ite;) 
{ 
    if(it->second._id == remove_id) 
    it = map.erase(it); 
    else 
    ++it; 
} 

Đây là an toàn vì bạn có thể xóa các nút riêng biệt trong cây mà không có sự lặp khác bị mất hiệu lực. Lưu ý rằng tôi đã không tăng biến lặp trong chính phần tử vòng lặp for, vì nó sẽ bỏ qua một phần tử trong trường hợp bạn xóa một nút.


† Bởi bây giờ, bạn nên đã nhận thấy rằng điều này sẽ tàn phá trong thứ tự các 's std::map, đó là lý do tại sao điều quan trọng là const - vì vậy bạn không thể ảnh hưởng đến trật tự trong bất kỳ cách nào sau mục đã được chèn.

+0

Cảm ơn bạn đã trả lời. Vì vậy, có bất kỳ cách thanh lịch nào để xóa mục khỏi std :: map mà không có mã xấu: 'void removeFromMap (FooMap & m, int id) { \t cho (auto it = m.begin(), end = m. end();! nó = cuối; ++ chúng ta) \t \t { \t \t if (nó-> second._id == id) \t \t \t { \t \t \t m.xóa (nó); \t \t \t ngắt; \t \t} \t} } ' – Reddy

+0

@Reddy: Không, không có cách nào khác mà tôi biết. Btw, nếu ID của bạn không phải là duy nhất, bạn sẽ chỉ xóa phần tử đầu tiên trong bản đồ. Nếu có, thì vòng lặp đó là tốt. – Xeo

+0

Vâng, tôi biết về nó. – Reddy

3

Bạn có thể sử dụng tìm và xóa cho bản đồ. Nó không thuận tiện như remove_if, nhưng nó có thể là tốt nhất bạn có.

int removeId = 6; 
auto foundIter = m.find(removeId); 

// if removeId is not found you will get an error when you try to erase m.end() 
if(foundIter != m.end()) 
{ 
    m.erase(foundIter); 
} 
Các vấn đề liên quan