0

I would like to understand how to use the Lambda functions in C++.

I'm using a custom types, as follows:

struct my_toy_t {
    uint32_t    id;
    cv::Rect    box;
    cv::Mat     data;
}

typedef std::map<uint32_t, my_toy_t*> my_toy_map_t;

And:

int main() {

    my_toy_map_t input_map;
    my_toy_map_t output_map;

    // Some insertions in input_map...

    my_toy_map_t::iterator it;
    for (it = input_map.begin(); it != input_map.end(); ++it)
    {
        if (check_cond(it->second->box)) {
            output_map.insert(std::make_pair(it->first, it->second));
            input_map.erase(it->first);
        }
    }
    return 0;
}

bool check_cond(cv::Rect box) {
    if (box.area > 100)
        return true;
    else
        return false;
}

It may be noted that my_toy_map_t is just a std::map<uint32_t, my_toy_t*>, and check_cond function checks a simple condition.

Is it possible to translate this code (insertion in output map and remotion from input_map if check_cond returns true) using a Lamba function?

8
  • 2
    You'd probably be better off without the pointers. Commented Aug 15, 2013 at 10:44
  • You are overusing the postfix _t. You would have a type name like my_marvellous_type_container_t in the future Commented Aug 15, 2013 at 10:44
  • 2
    std::copy_if together with std::inserter are your friends here. Commented Aug 15, 2013 at 10:46
  • 1
    Avoid remotioning while iterationing Commented Aug 15, 2013 at 10:49
  • 4
    The original code has undefined behavior. You erase the element the iterator points to, which invalidates the iterator. Commented Aug 15, 2013 at 11:08

3 Answers 3

2

May be std::copy_if and std::inserter ?

std::copy_if(input_map.begin(),input_map.end(),
             std::inserter(output_map,output_map.end()) ,
    [](const std::pair<uint32_t, my_toy_t*>& x ){ 
                             return (x.second)->box.area > 100;    
                              } 
                );

For removing I can think of this :

my_toy_map_t temp;

std::remove_copy_if(input_map.begin(), input_map.end(), 
                    inserter(temp, temp.end()),
                    [](const std::pair<uint32_t, my_toy_t*>& x ){ 
                                 return (x.second)->box.area > 100;    
                                  } );

input_map.swap(temp);
Sign up to request clarification or add additional context in comments.

3 Comments

In this way I have to visit two time input_map, but I could perform insertion/remotion during the same cycle.
@vdenotaris agreed, but the point was "I would like to understand how to use the Lambda functions in C++"
That ugly pair is more readable as my_toy_map_t::value_type const&
2

First of all, pointers are not needed. If you want to avoid the copies, use std::reference_wrapper.

Second, you are iterating ove a container, and modifying the container in the process. That has undefined behaviour: The previous iterators are invalid after a insertion/deletion operation.

What you are trying to do is a really a filtering process: Getting the elements of a container that pass a given condition, and fill another container with it.
That could be easily done with certain generic algorithms provided by the standard library. For example, the easiest way here is to use std::copy_if:

int main()
{
    std::copy_if( std::begin( input ) , std::end( input ) , std::inserter( output , std::end( output ) ) , [](const std::pair<uint32_t,my_toy_t>& pair ) { return pair->second.box.area > 100; });
}

As you can see, the function std::copy_if()expects a callable entity as the predicate of the filtering. In this case the eassiest way, and because you asked about how to improve the filtering with a lambda, is to pass a lambda function.

Reference:

7 Comments

how come you're using a back_inserter on maps ?
back_inserter on map?
@doctorlove Oh, thats true. I forget that is a map. I provide the generic solution. Give me a minute to fix it
There's not necessarily a problem with iterating over a container and modifying it at the same time; you just have to ensure the validity of the iterators.
the element of input_map is pair, you can simply convert to const my_toy_t& toy?
|
1

Could use std::for_each with mutable lambda

std::for_each(input_map.begin(), input_map.end(),
         [&output_map](const std::pair<uint32_t,my_toy_t*> &it) mutable{
    //   ^^                                                     ^^^^^^^
         if (it.second->box.area > 100)
         {
             output_map.insert(it);
         }
    });

Suggestion: you'd better use smart pointers + STL container instead of raw pointers raw pointer + STL container.

5 Comments

And if would I like to transfer the element from input_map to output_map?
you still need to erase it from input_map
Is there a way to perform insertion/remotion directly? I'm reading that is not good to remove an element while iterationing.
it's ok as long as you do it carefully. see: stackoverflow.com/questions/263945/…
Have a try with POW's new solution, looks like he has two nice solutions for you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.