1

Consider the following code, in which std::function is used three times to capture the methods of one class:

struct some_expensive_to_copy_class
{
    void foo1(int) const { std::cout<<"foo1"<<std::endl; }
    void foo2(int) const { std::cout<<"foo2"<<std::endl; }
    void foo3(int) const { std::cout<<"foo3"<<std::endl; }
};

struct my_class
{
    template<typename C>
    auto getFunctions(C const& c)
    {
         f1 = [c](int i) { return c.foo1(i);};
         f2 = [c](int i) { return c.foo2(i);};
         f3 = [c](int i) { return c.foo3(i);};
    }

    std::function<void(int)> f1;
    std::function<void(int)> f2;
    std::function<void(int)> f3;
};

This, however, will perform three copies of the class some_expensive_to_copy_class, which is inefficient as one could have guessed by the name.

Is there a workaround such that only one copy is made?

To emphasize it, I'm interested here in the approach using std::function, not void-pointers and also not the corresponding inheritance-based implementation.

davidhigh
  • 14,652
  • 2
  • 44
  • 75
  • [`std::bind`](http://en.cppreference.com/w/cpp/utility/functional/bind) with [`std::ref`](http://en.cppreference.com/w/cpp/utility/functional/ref)? – BoBTFish Jan 15 '16 at 21:35
  • @BobTFish: yes, I thought about that, but then the first `std::bind` would have to do a copy, whereas the seconds should reference this copy (not the external one, as this could be gone). Similar problem I guess. – davidhigh Jan 15 '16 at 21:37
  • I concur with T.C. The only thing that is being "copied" is the reference. The instance is not copied. – David Hammen Jan 15 '16 at 21:41
  • Using a std::shared_ptr may be appropriate in place of the type of c as an alternative if lifetime is an issue. – pticawr Jan 15 '16 at 21:44

1 Answers1

5

Make a copy with a shared_ptr, and capture that.

auto spc = std::make_shared<const C>(c); 
f1 = [spc](int i) { return spc->foo1(i); }
f2 = [spc](int i) { return spc->foo2(i); }
f3 = [spc](int i) { return spc->foo3(i); }
T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 1
    Or better yet, if you're going to end up with a `shared_ptr`, and you don't necessarily *need* a copy of the entire object, see if you can start with a `shared_ptr` in the first place. – Kyle Strand Jan 15 '16 at 21:44
  • This makes a copy (but only one copy) of `some_expensive_to_copy_class`. – David Hammen Jan 15 '16 at 21:45
  • 1
    @DavidHammen Yes, that's what the OP asked for. – T.C. Jan 15 '16 at 21:45
  • @DavidHammen In bold, even. – Kyle Strand Jan 15 '16 at 21:46
  • Why add `const`? Maybe having a modifiable object is the whole reason for needing a copy in the first place. – Kyle Strand Jan 15 '16 at 21:52
  • The copy may be attempting to keep the interface simple (avoiding extra std::make_shared outside the function). But it may be worth considering how expensive the copy is, and whether the extra code is worth it to avoid this one copy. – pticawr Jan 15 '16 at 21:56
  • @KyleStrand See http://stackoverflow.com/questions/18709647/shared-pointer-to-an-immutable-type-has-value-semantics – T.C. Jan 15 '16 at 21:56
  • @pticawr I'm not sure I understand your comment. Are you saying the OP's original request to avoid the extra copies should probably be reconsidered? TC: Thanks for the reference. – Kyle Strand Jan 15 '16 at 22:02
  • @Kyle The original request suggests that one copy is required - or at least that is how this answer has interpreted it. By instead using std::make_shared() in place of the original construction of the object, the potentially expensive copy would be eliminated. This does mean polluting the code with std::shared_ptr everywhere. – pticawr Jan 15 '16 at 22:05
  • @pticawr So you're reiterating what I said in the first comment on this answer? – Kyle Strand Jan 15 '16 at 22:09
  • @Kyle true, it's always good to avoid copying expensive_thing if you can. – pticawr Jan 15 '16 at 22:11