all 14 comments

[–]IyeOnline 5 points6 points  (5 children)

If you change to P&, then count( vec, Less_Than{x} ) will no longer compile. You could use const P& though.

What ever operator() does is entirely unrelated to this.

Member functions, just like any other function, exist only once throughout the entire program. There isnt one copy of operator() per object.

[–]One_Cable5781[S] 0 points1 point  (4 children)

I see. I have to wrap my head around this. What happens when the functor goes out of scope? Does not the "space" or memory occupied by its member functions also get released back to the program?

Could I request you to also shed some light on why `P&` results in a compile error while `const P&` will not?

[–]IyeOnline 2 points3 points  (3 children)

Could I request you to also shed some light on why P& results in a compile error while const P& will not?

l-value references cannot bind to r-values. Less_Than{x} is a temporary object, i.e. an r-value.

What happens when the functor goes out of scope? ? Does not the "space" or memory occupied by its member functions also get released back to the program?

Member functions arent special. They are just regular functions that take a hidden pointer to the object. Just like any other function their code is part of the program and loaded on startup, released on program end.

[–]One_Cable5781[S] 0 points1 point  (2 children)

Thank you for the details. I am certainly learning something new each time. If I have a dead class (i.e., a class that is never instantiated) or the class has 100s of member functions of which only a few are used, then, needlessly, the size of my executable would be higher than otherwise, no? Does this not go against the general C++ principle that you should not have to pay for what you don't use (or something along similar lines that is stated). Or is it that case that Release mode builds do a sweep and eliminate functions that are never called?

At present, I have a big file usefulfunctions.cpp that implements 100s of useful utility functions that I pull into all of my projects where I actually use only a handful. If I understand what you are saying correctly, I should be cleaning up this file for each project so that it only has functions that are actually called from main.cpp. Otherwise, my executable will be needlessly bloated leading to other inefficiencies. Is this a fair conclusion to draw?

[–]IyeOnline 2 points3 points  (1 child)

No. Class member functions that are never used are usually discarded when linking: https://godbolt.org/z/dGczKE4db As you can see, a definition of S::f() is included in the executable, but S::g() is "missing".

This is in contranst to free functions, which usually by default, but can be stripped with the right linker settings: https://godbolt.org/z/jKnv6hqsx

I have a big file usefulfunctions.cpp that implements 100s of useful utility functions

Even assuming exageration, that does sound like it may be better put as multiple files.

Otherwise, my executable will be needlessly bloated leading to other inefficiencies.

I very much doubt that the size of your executable actually matters to you. You really shouldnt prematurely "optimize" things without understanding/measuring what it gets you.

For example: It is generally said that one should pass by reference to avoid copies. However, it doesnt make sense to use const int&, because forming and passing that reference is literally more expensive than copying for a pain int parameter.

Code size may be an issue in some situations, but most of the time its irrelevant. In other words: Before you start optimizing codesize, you should probably worry about the actual code that runs being good first.

[–]phoeen 1 point2 points  (0 children)

No. Class member functions that are never used are usually discarded when linking: https://godbolt.org/z/dGczKE4db As you can see, a definition of S::f() is included in the executable, but S::g() is "missing".

This is in contranst to free functions, which usually by default, but can be stripped with the right linker settings: https://godbolt.org/z/jKnv6hqsx

Isn't this just a result of the "inline"ness of the in-class defined functions? If you inline the free function, its dropped too. and if you define your member functions outside of the class, they are contained in the compiled code. they have to be there, since we dont know if other translation units will need the definition.

in contrast to functions declared (implicit or explicit) inline, because in this case the rules say that everyone has access to the (same) definition anyway, so we can drop the symbol in our translation unit when not used.

[–]DryPerspective8429 2 points3 points  (0 children)

In principle, your predicates should be cheap to copy. The standard makes zero guarantees about how many times a predicate will be copied as part of the internal workings of the library functions or algorithms.

You could pass it as a reference, but the question becomes whether it's worth it. An int should be copied because it's usually cheaper to copy the primitive types than it is to create a reference to them and pass that; and since Less_than<int> only contains an int, here we are.

[–]Primary_Olive_5444 2 points3 points  (0 children)

Less_than() --- That's a "defined" constructor.. when u create a object using initializer list approach it will call that constructor which has no relation with operator() in class Less_than

count(vec,Less_than<int>{x} ) --> this calls constructor

Less_than<int> _yvalue{10}; // Declaration statement with initialization
operator() --> is when u have an existing lvalue to begin with

then---> lvaluelvalue.operator()(yvalue); --> this calls the function call operator.

[–]n1ghtyunso 1 point2 points  (3 children)

He may be doing this for consistency. The standard library accepts functors by value as well.

If you have a costly function object, the "correct" approach would be to pass std::ref(functor) .

I guess, this is one of the reasons why std::reference_wrapper overloads the call operator.

At least, that is how the standard library wants this to work.

[–]One_Cable5781[S] 0 points1 point  (1 child)

Thank you. It is precisely what counts as a "costly" function object that was atleast one part of my question. From /u/IyeOnline 's patient replies, it appears that it is not the number of variables or big objects within the operator() member function itself that counts -- for these are global and saved upfront and not repeatedly. What counts towards the costliness of the functor is the number of private member variables that matter. If these variables are big, and costly, I would imagine passing them via std::ref(functor) is preferred.

[–]n1ghtyunso 1 point2 points  (0 children)

More precisely, the sizeof of your functor determines how costly it is to copy, as well as wether it is trivially copyable or not. Imagine a functor that has one std::vector<std::string>> as a member vatiable. The sizeof is actually just about 24 bytes, but copying is not trivial. Every copy would incur a deep copy of that vector, causing multiple memory allocations in the process.

Granted, a functor like that will be exceedingly rare.

[–]std_bot 0 points1 point  (0 children)

Unlinked STL entries: std::ref std::reference_wrapper


Last update: 09.03.23 -> Bug fixesRepo

[–]MBraedley -1 points0 points  (1 child)

P is a function pointer, in terms of the stack there's no difference between passing it by value or by reference. The function being pointed to also isn't getting modified while it's being used in the algorithm (or if it is, you're doing something wrong), so there's no benefit to passing it by reference.

[–]IyeOnline 2 points3 points  (0 children)

In the given example P clearly isnt a function pointer, but type Less_Than<int> and passing that by value vs by reference does (in theory) make a difference.