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.
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With