1

If a c++ resource is managed via unique_ptr then does the destructor of the class need to free the heap memory it allocated or it gets free automatically when the unique_ptr goes out of scope? For eg. In below example if I plan to create a unique_ptr to Entity class and I don't add delete in destructor then what will happen?

class Entity
{
private:
    int* data;
public:
    explicit Entity(const int size) { data = new int[size]; } // acquire
    ~Entity() { delete[] data; } // release
    void do_something() {}
};

void functionUsingEntity() {
    Entity e(100);   // lifetime automatically tied to enclosing scope

    e.do_something();

} // automatic destruction and deallocation for e
Helena
  • 444
  • 2
  • 15
  • 1
    Where is `unique_ptr` in your code? – Evg Feb 19 '22 at 06:32
  • 2
    It will leak. Read about rule of 0/3/5. The class Entity has to manage its own resources, while unique ptr manages only Entity instance itself (when to call destructor). unique_ptr cannot magically determine which pointers are to be deleted because it might not be correct. Also, in this case it is better to use `std::vector`. – Incomputable Feb 19 '22 at 06:32
  • When a `unique_ptr` goes out of scope and destroys the pointed-to `Entity`, it will call the `Entity` destructor. It will not somehow figure out that `~Entity` needs to call `delete[] data;` if you do not put `delete[] data;` in there yourself. – Nathan Pierson Feb 19 '22 at 06:33
  • @Incomputable : so what's the significance of using unique_ptr for class Entity ? If the class itself has to satisfy rule of 5, then does it mean unique pointer only ensures that it's destructor will be called? If that's the case , then why use unique pointer? The destructor will be called regardless when the entity class object goes out of scope. Isn't it? – Helena Feb 19 '22 at 06:36
  • @NathanPierson - won't the destructor be called regardless if I use unique_ptr or not? Why to wrap the entity class with unique_ptr then? If the destructor is taking care of freeing the allocated memory then it will be called automatically when the entity class object goes out of scope. Why to wrap the entity with unique_ptr? – Helena Feb 19 '22 at 06:38
  • The question is _when_ will the destructor be called? If you do something like `Entity* foo = new Entity;`, then you have to write the corresponding `delete foo;` somewhere. If you do `auto foo = std::make_unique();`, then the pointed-to `Entity` is destroyed when `foo` goes out of scope. One possible situation where this is useful is if you have some polymorphic `Interface` and want a `std::vector`, but to avoid slicing while preserving the intended lifespan you make a `std::vector>` – Nathan Pierson Feb 19 '22 at 06:41
  • 2
    @Helena, unique_ptr is for pointers. If you need a pointer to Entity that has automatic lifetime management, then use unique_ptr. If you don't need a pointer (most of the time you don't need it), then just create an object where you need it (local variable, class member, global variable, etc). You will need proper copy operations though. So, read about rule of 0/3/5. – Incomputable Feb 19 '22 at 06:41
  • @Incomputable : is it right to say that unique pointer is good when we have stl container of pointers to entity? If we are using direct entity instances then it doesn't matter? – Helena Feb 19 '22 at 06:52
  • @NathanPierson - I am assuming the `Interface` in your example is a reference or a pointer and not instance/object? – Helena Feb 19 '22 at 06:53
  • @Helena, read about ownership (lifetime management), RAII and rule of 0/3/5 in context of ownership. Any further simplification will be either incomplete or downright wrong. I will not answer any more questions before you read about those topics. – Incomputable Feb 19 '22 at 06:55
  • @Incomputable - I have read all that. No worries if you don't want to understand what I am asking. Don't answer further as I too don't want to force you to use some time to understand my question. – Helena Feb 19 '22 at 06:58
  • @Helena, the statement is wrong. There is a world of usage cases not covered in that statement. It is not possible to enumerate all of the use cases, but it is possible to know the intuition and rules behind applying `std::unique_ptr`. I did not mean to offend and I do not think it sounded offensive. The example where the statement is wrong is using a special deleter when C based API returns you an object that does not have a destructor. – Incomputable Feb 19 '22 at 07:09
  • For a start, please clarify your question. Nowhere in this code does it use `unique_ptr`. It's not clear what is supposed to be managed. Looking at your title, it seems to be the destructor, is that what you mean? That said, as a new user here, please take the [tour] and read [ask]. – Ulrich Eckhardt Feb 19 '22 at 07:38
  • Each class is generally responsible for releasing what it manages. Your `Entity` dynamically allocates an array using a `new` expression, so is responsible for ensuring it is released using a corresponding `delete` expression. A `std::unique_ptr` will manage the lifetime of a dynamically allocated `Entity`, but does not drill down in order to release memory allocated by the `Entity` itself. – Peter Feb 19 '22 at 07:51

2 Answers2

1
int* data;

This is a pointer. When a pointer is destroyed, nothing happens to whatever it points to. If it is a last pointer to a dynamic allocation when it's destroyed, then that allocation will leak.

explicit Entity(const int size) { data = new int[size]; } // acquire
                                         ^^^^^^^^^^^^^^

Here, you allocate a dynamic array. If you don't deallocate it using delete[], then it will leak.

If a c++ resource is managed via unique_ptr then does the destructor of the class need to free the heap memory it allocated or it gets free automatically when the unique_ptr goes out of scope?

If a resource is owned by std::unique_ptr, then the destructor of std::unique_ptr will delete the resource. The dynamic array that you allocated is not owned by a std::unique_ptr. In order for it to be owned by a std::unique_ptr, you must change the type of the member to be a std::unique_ptr.

In below example if I plan to create a unique_ptr to Entity class and I don't add delete in destructor then what will happen?

Then the allocation that is not owned by a unique pointer will leak.


~Entity() { delete[] data; } // release

This is an incomplete attempt at implementing the RAII pattern. In order for deletion in the destructor to be correct, you must first ensure that the pointer is unique. That isn't currently enforced because your copy/move constructors and copy/move assignment operators make a copy of the pointer. Using any of those will result in undefined behaviour. You should follow the rule of 5 if you delete anything in the destructor.

Or, a better design would be to use an existing RAII class such as a smart pointer or a container i.e. follow the rule of 0:

class Entity
{
private:
    std::unique_ptr<int[]> data;
public:
    explicit Entity(const int size) : data(std::make_unique<int[]>(size)) {}
eerorika
  • 232,697
  • 12
  • 197
  • 326
0

When you create a std::unique_ptr<Entity> ptr to class Entity, and when ptr goes out of scope, it invokes the destructor of the class Entity. Now, if class Entity allocates any memory(as in this case) or is holding other resources, it is the responsibility of the destructor of class Entity to free the memory and release the resources. If you don't free the memory in the destructor, your application will end-up leaking memory.