How to delete pointer objects in a list?

Hello again!..
I'm trying to figure out how to delete pointers within a list. With vectors you can do it with a for loop since you can use square brackets []. However, you can't do that with lists:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <list>

class Object
{
    public: 
        Object() = default;
        ~Object() = default;

        void SetValue( int val )
        {
            mValue = val;
        }

        void PrintValue()
        {
            std::cout << this->mValue << std::endl;
        }

    private:
        int mValue;
};

int main()
{
        // list of objects
    std::list<Object*> objList;

        // Fill list
    for( int i = 0; i < 50; i++ )
    {
        Object* obj = new Object();
        obj->SetValue(i);
        objList.push_back( obj );
    }
}



After that I'm actually not sure how to even access items within that list, hence why I don't really know how to delete the pointers in it either. I've tried looking at some examples online, but there aren't many regarding lists, mostly vectors. However, in my program it's a little easier using lists.

Anyway, thanks a lot for taking the time!..
Last edited on
Do you mean that you simply want to remove the pointers from the list?

Or do you want to free up the memory that those pointers are pointing to?

Clarity is important!

EDIT:

I'm actually not sure how to even access items within that list


Lists are designed to support sequential access, rather than random access. So, to access the elements of a list, you should iterate over the list to access each element in turn. You can do this explicitly using std::list::iterator, but it's easier to simply use a range-based for-loop:

1
2
3
4
for (Object* obj : objList) 
{
  obj->PrintValue();
}
Last edited on
Note that using .erase()/.pop_back()/,pop_front() for a list of type pointer does call the destructor of the removed element. If the list is memory owning (as opposed to memory reference), then before an item from the list is removed, the destructor for the item needs to be used via delete.

Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <list>

struct mystruct {
	int a {};
	mystruct() {}
	mystruct(int aa) : a(aa) { std::cout << "construct " << a << '\n'; }

	mystruct(const mystruct&) = default;
	mystruct& operator=(const mystruct&) = default;

	~mystruct() {
		std::cout << "destruct " << a << '\n';
	}
};

int main()
{
	std::list<mystruct*> mylist;

	mylist.push_back(new mystruct(1));
	mylist.push_back(new mystruct(2));
	mylist.push_back(new mystruct(3));
	mylist.push_back(new mystruct(4));

	// BIG PROBLEMS!!
	mylist.erase(mylist.begin());

	mylist.pop_back();
	mylist.pop_front();

	for (auto& a : mylist)
		delete a;
}


which displays:


construct 1
construct 2
construct 3
construct 4
destruct 3


Note that the constructor is called 4 times - but the destructor only once!

Compare this with using managed memory and unique pointer (as memory owning):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main()
{
	std::list<std::unique_ptr<mystruct>> mylist;

	mylist.push_back(std::make_unique<mystruct>(1));
	mylist.push_back(std::make_unique<mystruct>(2));
	mylist.push_back(std::make_unique<mystruct>(3));
	mylist.push_back(std::make_unique<mystruct>(4));

	mylist.erase(mylist.begin());

	mylist.pop_back();
	mylist.pop_front();
}


Which displays:


construct 1
construct 2
construct 3
construct 4
destruct 1
destruct 4
destruct 2
destruct 3


showing that the destructor is called when an element is removed from the list.

If the container is to be memory-owning, then use managed memory - not a raw memory pointer!
Last edited on
Thanks a lot for your answers. I actually did make my list store unique pointers. I still need to learn more about lists but you've pointed me in the right direction, thank you!
FYI, it is possible to create an array of unique pointers....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <memory>

struct Foo
{
    Foo() { std::cout << "Foo ctor\n"; }
   ~Foo() { std::cout << "~Foo dtor\n"; }
};

int main()
{
   std::cout << "Example smart pointer array constructor...\n";

   std::unique_ptr<Foo[]> up(new Foo[3]);

   // three Foo objects deleted
}

Example smart pointer array constructor...
Foo ctor
Foo ctor
Foo ctor
~Foo dtor
~Foo dtor
~Foo dtor

As with all things array-ish a smart pointer array must have its size known at compile time, and is not resizable.
It's not resizeable, but the size of a managed pointer array can certainly be specified at run-time. They're really just a RAII for new/delete. Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <memory>

struct Foo
{
	Foo() { std::cout << "Foo ctor\n"; }
	~Foo() { std::cout << "~Foo dtor\n"; }
};

int main()
{
	size_t nos {};

	std::cout << "How many to create: ";
	std::cin >> nos;

	std::cout << "Example smart pointer array constructor...\n";

	const auto up {std::make_unique<Foo[]>(nos)};
}

I THOUGHT I had typed it was creation sizeable at run-time, but alas, I didn't.

Point well taken, thanks for the correction.
Topic archived. No new replies allowed.