Unique Pointer Example
Here’s an example of using unique pointers. There are no memory leaks in this example.
Notice how using unique pointers can simplify memory management. When unique pointers are deleted, or their container is deleted, the memory they point to is automatically destroyed.
#include <stdio.h>
#include <climits>
#include <vector>
#include <string>
#include <string.h>
#include <memory>
// Forwarded from C++14
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
class Resource {
public:
Resource(int resources);
std::unique_ptr<Resource> clone() const;
int val;
};
Resource::Resource(int resources)
{
val = resources;
}
std::unique_ptr<Resource>
Resource::clone() const {
return make_unique<Resource>(Resource(*this));
}
class Job {
public:
Job(const char * name); //simple constructor
Job(const Job &obj); //copy constructor
~Job(); //destructor
void print();
int val;
std::string s_name;
char * c_name = nullptr;
std::unique_ptr<Resource> resc = nullptr;
};
Job::Job(const char * name)
{
val = 0;
s_name = name;
c_name = strdup(name);
resc = make_unique<Resource>(1);
}
Job::Job(const Job &obj)
{
val = obj.val;
s_name = obj.s_name;
c_name = strdup(obj.c_name); // otherwise, when the original one is deleted, this would still point to freed memory
resc = obj.resc->clone(); // this is necessary since unique_ptrs cannot be copied. We need to deep-copy the pointed-to object.
// doing this in a "clone" method will allow us to use inheritance when we don't know the derived class
}
Job::~Job()
{
if (c_name)
free(c_name);
}
void
Job::print()
{
printf("%s has %d resources\n", s_name.c_str(), resc->val);
}
int
main()
{
Job job1 = {"0.shecil"};
Job * job2 = new Job("1.shecil");
auto job3 = make_unique<Job>(Job("2.shecil"));
std::vector<Job *> jobs1;
jobs1.push_back(new Job("10.shecil"));
jobs1.push_back(new Job("11.shecil"));
jobs1.push_back(new Job("12.shecil"));
std::vector<std::unique_ptr<Job>> jobs2;
jobs2.push_back(make_unique<Job>(Job("22.shecil")));
jobs2.push_back(make_unique<Job>(Job("23.shecil")));
jobs2.push_back(make_unique<Job>(Job("24.shecil")));
// removing element from vectors
delete jobs1.at(1); // delete the object
jobs1.erase(jobs1.begin() + 1); // remove the raw pointer from the vector
jobs2.erase(jobs2.begin() + 1); // remove the unique pointer from the vector, which will delete the object
for (const auto &job : jobs1) {
job->print();
}
for (const auto &job : jobs2) {
job->print();
}
// deleting jobs
// job1 does not need to be deleted, since when it leaves the scope, it will be deleted
delete job2; // need to delete job2, since we allocated it with new
// job3 does not need to be deleted, since when the unique_ptr leaves the scope, it will delete the pointed class
// we need to delete the jobs in jobs1, since when the vector leaves scope, the raw pointers won't get freed
for (const auto &job : jobs1) {
delete job;
}
jobs1.clear(); // good manners to clear the array, otherwise the values are still pointers, but to bad memory
// no need to delete the jobs in jobs2, as when the vector leaves the scope, it will be deleted, which will delete all the unique_ptrs
return 0;
}