Am I abusing politics?

I often use policies in my code, and as a rule, I am very pleased with this. But from time to time I come across the fact that I use this template in situations where policies and runtimes are selected, and I developed habbits to work on such situations. Usually I start with something like this:

class DrawArrays { protected: void sendDraw() const; }; class DrawElements { public: void setIndices( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); protected: void sendDraw() const; }; template<class Policy> class Vertices : public Policy { using Policy::sendDraw(); public: void render() const; }; 

When a policy is selected at runtime, I have different options for dealing with the situation.

Different code paths:

 if(drawElements) { Vertices<DrawElements> vertices; } else { Vertices<DrawArrays> vertices; } 

Inheritance and virtual calls:

 class PureVertices { public: void render()=0; }; template<class Policy> class Vertices : public PureVertices, public Policy { //.. }; 

Both decisions consider me wrong. The first one creates an unacceptable mess, and the second one introduces overhead for virtual calls, which I tried to avoid using policies first.

Are there enough correct solutions or am I using the wrong template to solve the problem?

+4
source share
5 answers

Use the second version. Virtual calls are more expensive than static calls because they require additional pointer lookups, but if "sendDraw" does some real drawing, you won’t notice the difference. If you really have a performance problem later, use the profiler to find out where the problem is and fix it. In the (extremely unlikely) case that invoking a virtual method is actually a performance issue, you can try to optimize it using policies. Until then, write the code that is most suitable for maintenance, so you have development time that needs to be optimized later.

Remember: premature optimization is the root of all evil!

+4
source

I don’t see anything wrong with the first - it doesn’t seem like a useless mess to me, although there is not enough code to determine if there can be better refactoring.

0
source

In general, if you want the behavior to change at runtime, you will have to pay some overhead for this, whether it is a switch / if statement or a virtual call. The question is how many times do you need runtime. If you are very sure that you will have only a small number of types, then the switch statement may indeed be appropriate. Virtual calls offer more flexibility for expansion in the future, but you do not need this flexibility; it depends on the problem. However, there are many more ways to implement your “switch statement” or your “virtual call”. Instead of the / switch, if you can use a visitor template (more serviced), and instead of virtual calls, you can use function pointers (when it does not make sense for the class itself to specify the behavior that is called at run time). Also, although I disagree with everything the author says (I think he artificially makes his idea and OOP mutually exclusive), you might be interested in Data-Oriented Programming , especially if you are working on rendering as your class names suggest.

0
source

Why are you opposed to virtual challenges? Are the overheads significant to you? I think the code becomes more readable when you express what you want to do by writing an interface and various implementations instead of some unreadable patterns.

In any case, why do you inherit Vertices from the Policy class? You already have a template argument. It seems that the composition here is more appropriate. If you use inheritance, you can have only one class without a Vertices template and change its behavior by passing different Policy objects - this is a strategy template.

 class Policy { public: void sendDraw() const =0; } class Vertices { public: Vertices(Policy * policy) : : policy(policy) { } void render() { // Do something with policy->sendDraw(); } } 
0
source

If you do not put drawing calls on the display list, then the array data should be copied when it is drawn. (Either the calling block is blocked until the GPU is executed, or the driver does not copy it from the application memory to a safe place.) Thus, the virtual function will not be a problem. And if you put them in a display list, then a virtual function will not be a problem, because it only installs once.

And in any case, PCs make virtual calls very quickly. They are not free, it’s true, but if you draw (say) thousands of vertex sets per frame, then an additional call to the virtual function for a draw is unlikely to break the bank. Of all that you need to think about in advance, avoiding the use of a virtual function in the situation for which the virtual functions are intended, is probably one of the less important. Avoid unnecessary virtual functions; really useful virtual functions are innocent until proven guilty ...

(By drawing more vertices per call and changing the shader, the shader constants, the vertex format, and the display state settings are less likely to bring big dividends.)

0
source

Source: https://habr.com/ru/post/1305770/


All Articles