Search code examples
c++pointersapi-design

How to indicate C++ ownership of pointer


Let's say I have a class:

class Scheduler {
    Scheduler(JobService *service);
    AddJob(JobID id, ISchedule *schedule);
}

The constructor takes a pointer to the service, but Scheduler does not take ownership of the service pointer. Service pointer is assumed to be released by the caller.

AddJob case is the opposite. Schedule lifetime is managed by the scheduler and when job is no longer needs to run schedule memory is released.

From the API point of view it is not clear who takes ownership of the pointer and who does not. I wounder if there are some techniques to indicate the intent through API design and not through documentation. To make it a bit more fool proof and obvious.

If I could, I would construct instance of ISchedule, but it is an abstract class in C++ (interface) and thus it would not be practical to create Add overloads for each type of schedule. So, I have to take a pointer in Add.


Solution

  • The number of scenarios is larger than just two.

    class Scheduler {
    
        // pass the raw pointer (or use a reference) to expresses
        // no ownership transfer (The passed in object will no longer be  
        // needed after the pointer or reference becomes invalid)
        Scheduler(JobService* service); 
        Scheduler(JobService& service); 
    
        // use a std::unique_ptr to pass ownership
        AddJob(JobID id, std::unique_ptr<ISchedule> schedule);
    
        // use a std::shared_ptr to pass shared ownership
        // when the passed in object needs to outlive either the caller
        // or the receiver and either one may need to delete it
        SomethingElse1(std::shared_ptr<Stuff> stuff);
    
    
        // use a std::weak_ptr to pass shared ownership
        // when the object may, or may not outlive
        // the receiver and the receiver needs to be able to detect
        // if the pointer is still valid (like an intermittent service)
        SomethingElse2(std::weak_ptr<Stuff> stuff);
    };
    

    References:

    R.30 Take smart pointers as parameters only to explicitly express lifetime semantics

    R.32 Take a unique_ptr parameter to express that a function assumes ownership of a widget

    R.34 Take a shared_ptr parameter to express that a function is part owner