Forums before death by AOL, social media and spammers... "We can't have nice things"
|    comp.lang.c++.moderated    |    Moderated discussion of C++ superhackery    |    33,346 messages    |
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
|    Message 32,477 of 33,346    |
|    Kaba to All    |
|    Layered data structures    |
|    13 Jul 12 17:23:52    |
      From: kaba@nowhere.com              Hi,              In the following is a generic problem concerning the design of data       structures in C++11. I have found 4 ways to solve the problem (listed       below), but I'm not completely happy with any of them. Can you find a       better solution?              ### Problem              Consider data structures A and B, where B refers to parts of A.       Then the modification, or destruction, of A, invalidates the state       of B. How can we guarantee that A is not modified or destructed       while B is referring to A?              Concrete example. We create a grammar-object to represent a context-free       grammar, and then want to generate different kinds of parsers for the       grammar, such as LR, LALR, and NLALR parsers:               Grammar grammar;        // ...        LrZeroAutomaton lrZero(cGrammar);        LalrAutomaton lalr(cGrammar);              The automata will refer back to the productions of the grammar.              ### Option 1: Documenting              In this option we simply state in documentation that A must not be       modified or destructed when it is referred to in B, and leave it to       the user to enforce this. This approach simply begs for bugs.              ### Option 2: Versioning              In this option the A has a version number associated with it.       This version number is incremented every time a mutating operation       is called on A. Before accessing A, the B always checks for the       current version number of A against the version number of A when       creating B. If the version numbers do not match, an error is       generated. A problem with this approach is that not all mutating       operations may go through A. This is the case when A offers direct       access to some of its parts. Otherwise this can be seen as a rule       which the user is required to follow, with the library checking for       the rule at run-time. We would rather want to check the condition       at compile-time.              ### Option 3: Transferred ownership              In this option A is moved into B. This guarantees that B can not       be modified or destructed, as long as A exists and refers to B.       The A can release the ownership of B to outside, given that it       also clears its state. The problem with this approach is that there       can be only one data structure B which can refer to A.              ### Option 4: Read-only objects              In this option A is moved into a read-only-object. This is an object       which contains a shared_ptr to an A to which A is move-constructed.       Copying a read-only object copies the shared_ptr, not the A, thus       making it possible to have multiple references to A. The       read-only-object can only be used to access a const-reference of A. The       read-only-object can release its object to outside given that it only       has one single reference. The B object accepts a read-only-object of A,       instead of A. This approach fixes the problem with option 3. The problem       with this approach is that it is a bit awkward to use:               Grammar grammar;        // ...        ReadOnly |
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
(c) 1994, bbs@darkrealms.ca