0

In case the question is a bit vague, let's use the example class Paper.

Let's say I have a dynamically allocated array of pointers:

Paper** myFolder;

and later, somewhere, it gets filled up with n pointers:

myFolder = new Paper* [n];
//trimmed - make each pointer in myFolder point to something

When we're done with myFolder, we need to delete each Paper before deleting the Paper** itself:

for(int i = 0; i < n; i++)
    delete myfolder[i];

My question: That code isn't very "pretty" now that C++11 and up have for each loops. How can I delete a dynamically allocated array of pointers work with the "for-each" syntax? The following is apparently syntactically incorrect:

for(Paper* p: myFolder)
    delete p;

or even

for each (Paper* p in myFolder)
    delete p;

Additional Info: myFolder is not an array of arrays. It is an array of pointers. Why? Because the objective is to take advantage of polymorphism. Paper may be subclassed, hence myFolder is an array of pointers rather than an array of objects.

Also: of course std::vector is a better approach than using raw pointers. The question is theoretical and regards only the new C++ syntax. I'm not looking for advice on how to redo this code.

ayane_m
  • 962
  • 2
  • 10
  • 26
  • 3
    [Ever Used Smart Pointers?](https://techoverflow.net/blog/2012/09/17/c11-iterate-over-smart-pointers-using-foreach-loop/) – amanuel2 Oct 06 '16 at 22:33
  • for(Paper* p: myFolder) is incorrect because the range for-loop requires the collection to provide begin() and end() iterators—and a raw pointer doesn't. – alexc Oct 07 '16 at 01:10

3 Answers3

2

You could use std::for_each with some pointer arithmetic.

std::for_each(myFolder, myFolder + n, [](Paper* p){ delete[] p; })

However in the spirit of using modern C++, I would discourage using manual memory manipulation at all and using something with RAII

std::vector<std::vector<Paper>>
Community
  • 1
  • 1
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • 2
    I will have to say , that `std::foreach` code looks a lot more unreadable or should i say "uglier" , than the previous normal for loop the OP Presented. – amanuel2 Oct 06 '16 at 22:39
  • As the OP requires polymorphism, he will require std::vector or even std::vector> – Hennio Oct 07 '16 at 10:24
1

As you want polymorphism, you need to hold pointers to your objects. You currently use a pointer to a dynamically allocated array

Paper** myFolder;

There is no need to manually control the allocation of the array, you can easily use

std::vector<Paper*> myFolder;

When destructing the folders, beautifully:

for(auto paper : myFolder) 
    delete paper;
Hennio
  • 433
  • 2
  • 18
0

Raw pointers should really be avoided.

Below is an example to use std::vector for your problem.

#include <vector>

class Paper {
};

class Folder {
    // A folder contains a vector of papers.
    std::vector<Paper> m_papers;

public:
    // Method to add a paper to the folder. Use Move semantics for performance.
    void AddPaper(Paper && aPaper) {
        m_papers.push_back(std::move(aPaper));
    }

    // A read-only getter.
    const std::vector<Paper> & Papers() const { return m_papers; }
};

int main()
{
    std::vector<Folder> folders;  // All your folders.
    Folder aFolder;   // Create a folder.
    aFolder.AddPaper(Paper());  // Add paper to the folder.
    folders.push_back(aFolder);  // Add a folder.

    for (const auto & f : folders) {
        for (const auto & p : f.Papers()) {
            // Read each paper here.
        }
    }
}

When using std::vector, a ranged for loop can be used to access each element:

for (const auto & f : folders)
Garland
  • 911
  • 7
  • 22