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 maximise 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.