Class containing a reference OR a value of finite number of classes

I am making a few classes which allocates a lot of memory. Therefore, I need to minimize the number of copy operations.

While working on it, I wished that if I had a template class that contains a type(T) or a reference(T&), not both, so that I could make a code like below:

template<typename T>
class EITHER {
    /* some code */
};

class A { /* some code */ };

void f(A &a) { /* some code changing `a` */ }

int main() {
    A a(42);
    std::vector<EITHER<A>> v;
    
    v.emplace_back(a); /* stored as a reference */
    v.emplace_back(A(72)); /* stored as a value (possibly moved) */

    f(a); /* okay. */
    f(v[0]); /* okay, modifies `a` through a reference stored in `EITHER<A>`. */
    f(v[1]); /* okay, modifies the value stored in `EITHER<A>`. */

    {
        A b(3);
        v.emplace_back(b); /* stored as a reference */
    } // Now `b` is destructed, `v[2]` holds the latest value (not reference) of `b`.
    f(v[2]); /* okay, modifies the value stored in `EITHER<A>`. */
}

I’m pretty sure this will be useful in many cases, but I have no idea how to implement this.

  • std::variant cannot store references.
  • std::optional<T> with T* might do the job, but I’m pretty sure there should be a way to handle this like std::optional. If std::optional stores or does not store the type, EITHER will store only the type T or the type T&.
  • Lastly, it seems like I have to memo if the original variable is destructed or not, but will it be possible without modifying A?

Please remember that there are finitely many classes that EITHER will be applied, if this is useful.

I wish I could get any solution or a feedback for this question. Thanks.

p.s. Aiming c++20.

Answer

References have the important property that they are supposedly always valid (if you don’t mess up), which discerns them from pointers which might also be nullptr.

You need to use a pointer internally. You can convert back-and-forth between pointers and references, so you could still take a reference in and always hand a reference out.

Problem is that you are introducing optional ownership with your Either class. Expect many programming errors down the line. It already starts with your example b where you expect handing a reference which is supposedly later magically converted to a value.

I suggest to look into how unique_ptr might solve your problem instead. With unique pointers it is clearly defined that the container will take up ownership of its contents. Callers can wrap existing objects in a unique_ptr, or if they were created on the stack, move them into make_unique(), as well as creating fresh objects with make_unique(). Finally, you won’t have a wrapper class or anything, everybody versed in C++11 should be able to understand how a std::vector<std::unique_ptr<A>> v; works.

Leave a Reply

Your email address will not be published. Required fields are marked *