Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vector of smart pointers destructor call

Why does the Node destructor get called only once instead of 5 times in the code below?

#include <iostream>
#include <vector>
#include <memory>

struct Node {
    ~Node() {std::cout << "Node destructor called.\n";}
};

void foo() {
    std::vector<std::shared_ptr<Node>> nodes(5, std::make_shared<Node>());
}

int main() {
    foo();
    std::cout << "foo() ended.\n";
}
like image 948
prestokeys Avatar asked Dec 14 '15 18:12

prestokeys


People also ask

Do smart pointers call destructor?

The smart pointer destructor contains the call to delete, and because the smart pointer is declared on the stack, its destructor is invoked when the smart pointer goes out of scope, even if an exception is thrown somewhere further up the stack.

How do you call a destructor from a vector?

The vector will automatically call the destructors of the "smart pointers" and these destructors, in turn, will destroy the pointed objects. This "link" can only be implemented explicitly, inside the "smart pointer's" destructor, which is why ordinary raw pointers can't help you here.

Do you need a destructor with smart pointers?

Boost smart pointers by themselves don't have anything to do with the need for a destructor. All they do is remove the need for you to call delete on the allocated memory that they are effectively managing.

Does vector clear call destructor?

char * has no destructor, but vector::clear does call the destructor when the type has it. Yes manual deallocation is necessary unless you store smart_ptr(unique_ptr) in the vector. Formally, your loop has undefined behavior.


2 Answers

Your vector contains five copies of the original shared pointer, all sharing ownership of the one single pointee.

To create five separate objects, each owned by one shared pointer, write it like this:

std::vector<std::shared_ptr<Node>> nodes;
for (int i = 0; i != 5; ++i) nodes.push_back(std::make_shared<Node>());
like image 76
Kerrek SB Avatar answered Nov 09 '22 05:11

Kerrek SB


Kerrek SB explained the situation well, but to do what you want to do in a different way, you could also the std::generate_n algorithm:

std::vector<std::shared_ptr<Node>> nodes;
std::generate_n(
    std::back_inserter(nodes),
    5,
    std::make_shared<Node>);

This is more along the lines of what you thought you were doing originally.

Or, similarly:

std::vector<std::shared_ptr<Node>> nodes(5);
std::generate(nodes.begin(), nodes.end(), std::make_shared<Node>);
like image 23
Barry Avatar answered Nov 09 '22 05:11

Barry