Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

unary_function or static method in local class???

Posted on 2001-07-03
19
Medium Priority
?
324 Views
Last Modified: 2013-12-14
Hi,
my question: here are 2 ways of doing the same thing (I think...). The recommand (read documented) way by STL doc, effective STL, etc. and another way, more concise and readable that I came up with?

I prefer the second way where I don't need to declare the utility class in the global scope (or file scope).

Situation: map of pointers to be cleaned in destructor (both key and values are pointers and need to be deleted).

STL's way:

class CDomainManagerDeleter :
   public std::unary_function<std::pair< wchar_t *, CDomainManager::CDomainElementInfo * >, void>
{
public:
   void operator()(const std::pair< wchar_t *, CDomainManager::CDomainElementInfo * >& pair)
   {
      delete[] pair.first;
      delete pair.second;
   }
};
CDomainManager::~CDomainManager()
{

   //Delete all * Class in the map
   std::for_each(m_mapDomain2ID.begin(), m_mapDomain2ID.end(), CDomainManagerDeleter());

   //Then Kill the Map
   m_mapDomain2ID.clear();
}

The other way
CDomainManager::~CDomainManager()
{
   struct CDomainManagerDeleter
   {
   public:
      static void DeleteMapElement (const std::pair< wchar_t *, CDomainElementInfo * >& pair)  
      {
         delete[] pair.first;
         delete pair.second;
      }
   };

   //Delete all * Class in the map
   std::for_each(m_mapDomain2ID.begin(), m_mapDomain2ID.end(), CDomainManagerDeleter::DeleteMapElement);

   //Then Kill the Map
   m_mapDomain2ID.clear();
}

BTW, I know I should used wstrings... :)

Are there any circumpstances in which one should/should not be used???

Thanks!
0
Comment
Question by:antoinebf
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 7
  • 4
  • +1
19 Comments
 
LVL 22

Expert Comment

by:nietod
ID: 6250373
Honestly that is really one way, not two.  there are 100s of minor variations of that one way you could try.  

Use whichever you feel comfortable with.

>> Are there any circumpstances in which one should/should not be used???
I doubt it.
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6251872
Oh, I think there is a difference - didn't spot it at first.  

The first version is better, in the second you are passing a function pointer (not a function object) - so the struct that conttains it is actually redundant in this case.  This is much less efficient in general because there is no opportunity for the compiler to in-line the function.  

Function Objects are a good thing to understand - a lot of the power of templates in general and the STL in particular comes from understanding them.
0
 
LVL 5

Expert Comment

by:proskig
ID: 6252193
I can recommend to try benchmark this code on your compiler (with optimization turned off). The most of compilers does not optimize STL well enough.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 9

Expert Comment

by:jasonclarke
ID: 6252227
> I can recommend to try benchmark this code
> on your compiler

it is not a performance issue.

Function objects are generally a better way to go with the STL (as opposed to function pointers) - they offer more flexibility and power.  In addition to this they offer potentially improved performance.

My contention is that unless you have a good reason not to, a function object is a better choice than a function pointer, in general.
0
 
LVL 22

Expert Comment

by:nietod
ID: 6252234
I would have thought that sort of optimization--the removal of an object that contains no data and the inlining of one of its fucntiosn to be a little bit unlikely.  But a test shows that indeed VC does so.   So the functor code has that advantage, but its a very very small advantage.  (certainly no more than 50 clock cycles, per item, if you have 10,000 items that is at most 500,000 clock cycles, on a 100Mhz machine--which you can get at an antique store--that would only be a difference of 1/200th of a second.)   So it isn't a big difference.  When you consider the fact that within that code the delete operations will be the bottlneck, they are likely to takes 100s or 1000s of times longer than the code that calls the delete.  I woudl say it is very insignificant.

I still say use whichever you feel comfortable with, the time savings is imeasurabel.
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6252250
> I still say use whichever you feel comfortable

the principle is a general one, and I agree that in case the difference is insignificant.

Sometimes, it is significant, however.  The obvious case is passing a comparison functor to std::sort.  Here the lack of a function call for comparison can be very significant - the reason why std::sort is in general faster (if you use it correctly) than qsort.

But as I say,  I think function objects are a good habit to get into.  So I would say use them unless you have a good reason not to.

The second example above is not a function object - it is a wrapper around a static method.  That method could be anywhere, the containing struct is irrelevant.
0
 
LVL 22

Expert Comment

by:nietod
ID: 6252329
>> I think function objects are a good habit to get into.  So I would
>> say use them unless you have a good reason not to.
That I definitly agree with

>> it is a wrapper around a static method
And no such wrapper is really needed.  You could hust specify an unbound function or a static function of the CDomainMainager class etc.  That is why I said there are 100s of minor variations between them.  That is why I think the 1st consideration should be what is most convenient.   There are no significant differences, like in terms of safety, code readability, code maleability etc, the difference in speed is probably never all that signfiicant and really depends on the optimizer.
0
 
LVL 2

Author Comment

by:antoinebf
ID: 6252612
OK,
so if there both as powerful performance wise, I should get used to using function objet... there probably more practicle and versatile.

If VC optimizer does something strange, (because I will certainly test both... it's intriguing) I'll let you know!

But for now, let's go with functors.

Thanks

A.
0
 
LVL 22

Expert Comment

by:nietod
ID: 6252676
>> both as powerful performance wise,
If you mean "speed", no.  We can't make absolute statements about the relative speed of these two approaches--or their many variations.  But there is a good chance that the functor method will let the compiler in-line the function and make things a bit faster.  But this is not absolute.  it depends on the compiler.  its even possible that on some compilers  it might work the other way around--less likely.  But in any case, the difference is not likely to be that significant.

>> I should get used to using function objet
Not for reasons of speed, but because they help you to write powerful code that tends to be much simpler and safer than the alternatives, like function pointers.   This example doesn't really begin to show the power of functors.

>> If VC optimizer does something strange,
I did test it under the VC optimizer and indeed it did inline the functor code and not the static function code. (as Jason suggested/predicted).   Now if you had delcared that function as inline--which I did not test, it might have inlined it too.  you might also have tried it without the enclosing struct as another attempt to encourage it to inline.   I didn't try either  of these.  
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6252711
> Now if you had delcared that function as inline--
> which I did not test, it might have inlined it too.

no, it can't do it.  The reason is that what you are passing in the second case is a function pointer not an object.

The compiler will see the call through a function pointer and will make the call - there will be no opportunity to in-line the code.

The object works, because in the the syntax of the call in for_each, something like:

template <class InputIter, class Function>
Function for_each(InputIter first, InputIter last, Function f)
{
  for ( ; first != last; ++first)
    f(*first);
  return f;
}

the code f(*first) is no longer a call through a function pointer, it is an invocation of operator() on the class passed as Function.  The compiler *can* inline the code for operator().
0
 
LVL 2

Author Comment

by:antoinebf
ID: 6252942
Regarding inlining, do compilators optimizations inline by themselves or it has to be specified explicitely? It probably has to be specified, but I want to be to be sure...
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6252953
> Regarding inlining, do compilators optimizations inline by themselves

no, they can only in-line if explicitly requested to do so, but remember that a function which is defined inside a class header is an implicit request for inlining.

So:

struct A
{
   void f1() {} // Could be in-lined
   void f2();
   void f3();
};

inline void A::f2() {} // Could be in-lined
void A::f3() {} // Cannot be in-lined

0
 
LVL 9

Accepted Solution

by:
jasonclarke earned 200 total points
ID: 6252962
> Regarding inlining, do compilators optimizations inline by themselves

the other point is, compilers are free to ignore a request, it is only a hint.

Compiler's almost never inline when in debug mode, for example.

A compiler will not inline if it thinks that for some reason a function is too complicated.  virtual functions are often not inlined, for example.
0
 
LVL 2

Author Comment

by:antoinebf
ID: 6252976
Thanks, it's great to know.
0
 
LVL 2

Author Comment

by:antoinebf
ID: 6252979
thanks for all your comments!
0
 
LVL 22

Expert Comment

by:nietod
ID: 6252997
>> no, they can only in-line if explicitly requested to do so,
That is not true.   When was the last time I said that about one of Jason's posts?   The inline keyword is only a suggestion.  It certainly might not inline a function that is not declared inline (or defined in a class/struct).  but the reverse is also true, it might inline a function that is not declared inline.  it is up to the compiler.  The VC compliler, for example, defaults to a mode where it considers all possible functiuons as candidates for inlining and inlines them if its analysis demonstrates it would be beneficial.

0
 
LVL 22

Expert Comment

by:nietod
ID: 6253007
>>virtual functions are often not inlined, for example.
Like if the compiler can't determime what type of object is invoking the call at compile time.   However, in simple cases it can make this determiantion and may inline the virtual fucntion.
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6253256
> That is not true.   When was the last time

I suppose this is true, the compiler can do as it chooses as long as the behaviour is correct.

However, I suppose the thing that normally prevents it is external linkage.  A function that is not defined in the same file as it is declared cannot be called cannot be inlined if it is or might be called from another file (assuming a normal linker) - because of the one definition rule.

However, I still think the compiler *can't* inline (assuming normalish behaviour) with the for_each type of thing, because the template expansion of for_each will look something like:

assuming:

typedef std::map<whatever>::iterator iter

typedef void (*funcptr) (const std::pair<whatever>& pair);

then the expansion is:
 
funcptr for_each(iter first, iter last, funcptr f);

then the compiler won't be able to see through the function pointer to inline it.  In general (due to the one definition rule), it also cannot optimise further becuase it must use the same definition for any other invocations using the same type - which may use a different function pointer.

0
 
LVL 22

Expert Comment

by:nietod
ID: 6253372
>> A function that is not defined in the same file as it is
>> declared cannot be called cannot be inlined
theoretically it could be, but that would be very difficult.  I doubt any compilers/linkers currently do so but maybe sone day.   In many ways, doing so would probably not be much harder than exported templates, but very few if any compilers support them yet.

>> because of the one definition rule.
the rule only applies to the source, not the final product.  So if a compiler can manage to inline an externally defined fuction--with the help of a project database or something like that, its not a violation of the one definition rule.

>> when the compiler won't be able to see through the function pointer to inline it
but it will expand the for_each code.to.  Then you will have a case where a pointer varaible is assigned a value, never changed and used.  that pointer variable is a good candidate for optimization away.  Then you have a call to a function.  It woudl be a good time to in-line that function....

Actually, a look at VC's code shows that it did optimize away the pointer to the function.   It however did not inline the function after that.   It made a direct call to the function from the loop, wherase the first code place the function's code right in the loop.  maybe declaring the funciton as inline might have helped.  Maybe VC 7 will do a better job.   (Although I'd say I'm amazed at what Vc 6 does do, and sometimes amazed at what it doesn't do.)
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

704 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question