Search code examples
c++pointersapi-design

Returning pointers to interfaces but keep ownership & lifetime to the provider


I have the following set of libraries

  • Some interfaces
  • Provider library. It will provide objects with defined interfaces.
  • Consumer library. It uses objects of defined interfaces.
  • Coordinator library. Uses the Provider to create objects and pass them to the consumer.

My problem is about the API design of the Provider. Let's take an example:

class Provider
{
    // One way is to return a reference to an owned object.
    // This is useful because no pointers are returned
    // so that no one will be asking about ownership and lifetime.
    // - The provider owns the object and
    // - The lifetime of the object is the same as the provider.
    const ObjectInterface &getObject(int id) const;
}

These are the semantics I want to keep.

  • The provider owns the object and
  • The lifetime of the object is the same as the provider.

But the previous interface will not be helpful in case a set of objects need to be returned.

class Provider
{
    // This is the easiest way.
    // Is this the best way?
    std::vector< ObjectInterface * > allObjects() const;

    // Using shared_ptr violates the semantics described above
    // and requires allocation on heap.

    // Using weak_ptr violates the semantics described above
    // and requires allocation on heap.

    // Using unique_ptr violates the semantics described above
    // and requires allocation on heap.
}

Is there a better way for designing this API to return pointers to interfaces whose concrete objects are owned by the provider while keeping the following semantics (which is the natural semantics of returning a reference (&) to an object)?

  • The provider owns the object and
  • The lifetime of the object is the same as the provider.

Solution

  • If you want to return references, you can use std::reference_wrapper:

    #include <functional>
    #include <vector>
    #include <cstdio>
    
    struct A
    {
        std::vector<int> objs{1, 2, 3};
    
        std::vector<std::reference_wrapper<int>> allObjects()
        {
            return std::vector<std::reference_wrapper<int>>(objs.begin(), objs.end());
        }
    };
    
    int main()
    {
        A a;
        for (auto ref : a.allObjects())
            printf("%i\n", ref.get());
    }