Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 821
Sergei G Avatar asked Jul 13 '17 17:07

Sergei G


People also ask

What is ownership of pointers?

Pointer variables imply ownership of the objects that they point to. When a method (or function) has a local variable that points to an object, that variable is said to own the object being pointed to.

What is ownership in C?

In C, there is no inherent ownership. Anybody who has and address of a variable can modify it (with some exceptions of course). If you want to introduce ownership, you'll have to do it yourself through Mutexes/Semaphores/etc.

How do you pass ownership in C++?

In C++11 we can transfer the ownership of an object to another unique_ptr using std::move() . After the ownership transfer, the smart pointer that ceded the ownership becomes null and get() returns nullptr.

What is a pointer in C __?

Pointers (C++) A pointer is a variable that stores the memory address of an object. Pointers are used extensively in both C and C++ for three main purposes: to allocate new objects on the heap, to pass functions to other functions. to iterate over elements in arrays or other data structures.


1 Answers

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

like image 118
Galik Avatar answered Oct 01 '22 06:10

Galik