Update of element in Array of CachedValue<> changes all values of objects with same Identifier in array?


#1

I’ve been working on refactoring my code to use ValueTrees. In the process I changed my String sample_file_path variable to a CachedValue<String>. This is a member variable of a class SampleSource and I have an array of 8 SampleSources. I want to let a user update the file path to pick a new sample but when the file path variable for any one SampleSource, the value is updated to the same String in each SampleSource. However, if I simply use a String instead of a CachedValue<String> my code works fine. So, I believe setting the file path in one object is changing the value in all objects automatically when using a CachedValue<>.

Specifically, the user sets a sample path for sample 1 in the GUI which calls some method which more or less says sample_source[1]->set_file_path('xyz.wav') and then later they might add a sample so sample_source[2]->set_file_path('abc.wav') is called. This however sets both file paths in sample_source[1] and sample_source[2] to be the same value. How can I prevent the ValueTree or CachedValue<> from automatically setting each to the same value?

Per cpr: I’m initializing the CachedValue by setting it in each SampleSource constructor with the code file_path_(get_state(), IDs::SampleSourceProps::file_path, get_undo_manager(), ""), where file_path_ is a CachedValue<String>. Then, there’s a method in SampleSource called set_file_path which looks like
void SampleSource::set_file_path(const String& path_to_swap) { file_path_ = path_to_swap; }.

IDs::SampleSource::file_path is an Identifier named file_path.

Please let me know if I should provide more info about something specific.


#2

I think it would be helpful if you would include the code for how you are configuring the CachedValue


#3

Thanks, I’ve updated my post.


#4

CachedValue binds a variable to a property in a ValueTree. While I am not personally using it, I have looked at the API in my usage of ValueTrees. And, if I am reading your code correctly, you are using the same ValueTree and Identifier for all of the CachedValues, which causes them to all bind to the same property. You need to give each path a specific property Id. IDs::SampleSourceProps::file_path_1, IDs::SampleSourceProps::file_path_2, etc. Another option would be to make them children, where you could use the same Identifier, because you would have a different ValueTree (child) for each file path. I’d have to reflect on things more to know if there is any benefit to that.


#5

Interesting, I thought that might be the problem. I’ve considered naming file_path1, file_path2 etc. but that wouldn’t allow for the number for SampleSources to grow without recompiling and adding more Identifiers. I’ll read up about making them all children. Thanks for that idea!


#6

Children are much more like entries in an array, so that is a better way to do it. You can add delete, and reorder them. And other pieces of code can respond to those events happening, through the various listeners. Otoh, you can generate Identifiers programmatically, that’s not the issue that would keep you from using properties. But, like I said, the child method feel more correct.


#7

I will give this a shot. I think that makes sense to me but I may be back for suggestions. Thanks.


#8

Looking back on my code, what still doesn’t make much sense to me is why changing the value without using any ValueTree code still changes all CachedValues. Since I’m specifically accessing each SampleSource in the array and updating them, not using Listeners etc. So the ValueTree shouldn’t change the value because I’m not telling the ValueTree to. However, obviously that’s not the case since it’s still changing.


#9

CachedValue is a ValueTree::Listener! That’s why it’s so cool, it binds a variable to a property of a ValueTree without you needing to set up all the Listener stuff yourself.

 // create a CachedValue wrapper around myString
CachedValue<String> myString;
// bind myString to the IDs::SampleSourceProps::file_path property in the 
// ValueTree returned by getState()
myString.referTo(getState(), IDs::SampleSourceProps::file_path, get_undo_manager());

So, now if you change the value of myString, it updates the ValueTree. And if somewhere else you update the ValueTree, then myString is updated.


#10

If you’ve not watched this video, the I highly recommend it!! :slight_smile:


#11

This makes a lot of sense, thanks. Also, I have seen the David Rowland video, that’s what inspired me to try ValueTree out.