I was doing an assessment for university regarding password cracking. They say that experience is something that cannot be learnt. Never that notion has been more true than today when I was attempting to create a list of lists:
List<List<string>>. I had "virtually" unbounded memory, but I had to make sure that I could maximize the number of attempts i.e. every operation mattered. In order to access this information fast I had to load in a bunch of passwords into the memory index them the best I could to quickly pick random passwords (I also added some caching but that's beyond the point). In total, I was using about 16 GB of memory.
The initial set up was not counted towards the total time. In order to avoid
NullPointerExceptions and using
if statements to verify if the inner list(s) were created or not, the plan was to instantiate all the lists upfront. Wishing to populate my list in one line of code I simply used
this.addRange(Enumerable.Repeat(new List<string>(), X)).
Then I run my unit test which added a value to
outerList[x] and it failed. However, the program seems to run fine, perhaps slower than expected, but otherwise fine. I debuged the test and it turned out that all the inner lists had
Count 0 before adding the value and all had
Count 1 after adding it. One list was updated, all of them would get updated.
After few minutes I did manage to track the problem.
Enumerable.Repeat(new List<string>(), X) creates only one object which is then copied X many times. In other words, it does not create a
new List X times, it copies the pointer to the object.
As they say, live and learn.