C ++: Why does this synchronization () not work in this composition template?

I am trying to create a progressbar class that can have an arbitrary number of subprogram bars using something similar to a composition pattern.

let's say I have this pbar class:

 class pbar { public: pbar(const int w) { width = w; } // already sets the ~pbar() {} void setwidth(const int w) { width = w; } // set the width to w void show() const; void sync(); void add(const pbar bar) { // add a subbar subbars.pushback(bar); } private: std::vector<pbar> subbars; // the sub-process progressbars int width; // onscreen width of the pbar }; 

As you can see, pbar has two members: width and routines (which themselves are pbars ). I am trying to implement a sync function that changes all the widths of pbars in subbars to match the type of pbar from which it was called:

 void pbar::sync() { for ( pbar bar : subbars ) { bar.setwidth(width); // first set the width of the subbar bar.sync(); // secondly make it sync up it subbars } } 

but this does not seem to work. I tried using this test program:

 int main() { pbar a(1); pbar b(2); pbar c(3); pbar d(4); c.add(d); b.add(c); a.add(b); a.show(); std::cout << "syncing" << std::endl; a.sync(); a.show(); } 

with the show function defined as:

 void pbar::show() const { std::cout << w << std::endl; for ( pbar bar : subbars ) { bar.show(); } } 

Expected Result:

 1 1 1 1 

but this:

 1 2 3 4 

It is strange that the show() function performs the correct iteration to all subclasses, but sync() does not seem to work (in fact, using cout , I confirmed that in fact, but it does not seem to have an effect).

What is wrong with my code? This is not using c++0x for loop, because I tried to use older iterator loops. I cannot find the mistake I made. I think this is due to the fact that I am changing the wrong pbar when using setwidth in sync .

disclaimer: this is actually part of a larger project, and the class is much more complicated than shown here, but I managed to reproduce the undesirable behavior using the above code (which, incidentally, is not copied in brackets and may contain typos)

+4
source share
4 answers

This is not using C ++ 0x type for loop

Actually, depending on what you really want to do, it can only be a loop based on the for range you are using.

As stated in the question, the subbars vector stores copies of the objects added to it - this may or may not be what you want. Suppose this is what you want. The range based on the loop you have right now in pbar::sync() :

 for ( pbar bar : subbars ) { // ... } 

subbars over the subbars vector, but the bar variable in this case is itself a copy of each element in this subbars vector. Therefore, any changes you make to this variable are simply lost after each iteration of the for loop.

However, if you change the for loop based on the range:

 for ( pbar& bar : subbars ) // note the `&` { // ... } 

Now bar is a reference to an object in the subbars vector, and the changes made to it will "stick to".

Remember, however, that since subbars contains copies of an object that have been added to it, these changes will not apply to the original objects. Whatever you want depends on what you want. If you want the changes to extend fully to the originals, you need to save the pointers (or smart pointers) to the originals instead of copies, and the ones mentioned in the answer are visier .

+3
source

The problem you are facing is that you are using the local variable "bar" in a loop in your sync () method. This makes a copy of each of your subclasses and manipulates the copy, not the original version (which remains in the vector). This is why you have not noticed that the changes are β€œstuck” when you later call the show () method.

Perhaps you can fix this by using a link instead of a regular variable. Try:

 for ( pbar &bar : subbars ) { ... } 

You might want to make similar changes to your addSubBar () method, as you also copy the values ​​you pass before storing another copy in the vector. You can skip one copy by making its parameter a link. Avoiding the second instance will require some caution when working with memory (which I will leave for another question).

+5
source

You must save pointers to sub pbars . In the current situation, you just save copies of sub pbars . Therefore, although they (internal copies) are changed, the external object does not change.

+4
source

you must save the pbars link instead of the instance.

0
source

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


All Articles