Solved

unary_function or static method in local class???

Posted on 2001-07-03
19
286 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
  • 7
  • 7
  • 4
  • +1
19 Comments
 
LVL 22

Expert Comment

by:nietod
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 9

Expert Comment

by:jasonclarke
Comment Utility
> 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
Comment Utility
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
Comment Utility
> 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
Comment Utility
>> 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
Comment Utility
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
Comment Utility
>> 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
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 9

Expert Comment

by:jasonclarke
Comment Utility
> 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
Comment Utility
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
Comment Utility
> 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 50 total points
Comment Utility
> 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
Comment Utility
Thanks, it's great to know.
0
 
LVL 2

Author Comment

by:antoinebf
Comment Utility
thanks for all your comments!
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
>> 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
Comment Utility
>>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
Comment Utility
> 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
Comment Utility
>> 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

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
Here is a helpful source code for C++ Builder programmers that allows you to manage and manipulate HTML content from C++ code, while also handling HTML events like onclick, onmouseover, ... Some objects defined and used in this source include: …
The viewer will learn how to synchronize PHP projects with a remote server in NetBeans IDE 8.0 for Windows.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

744 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now