Reputation: 83
Basically I am creating a basic shell program for a class project. I am stuck on iterating through the files/folders within a directory.
My error is in the function DisplayDirectoryContents()
class Directory
{
private:
map<string, pair<list<Folder>, list<File> > > directoryContents;
string directoryPath;
public:
list<Folder> getFolders() {return directoryContents[directoryPath].first;}
list<File> getFiles() {return directoryContents[directoryPath].second;}
string getDirectoryPath() {return directoryPath;}
Directory()
{
directoryPath = "root/";
File *file = new File("Test");
directoryContents[directoryPath].second.push_back(*file);
}
void DisplayDirectoryContents()
{
// Get files and folders from directory
list<File> files = this->getFiles();
for(int i = 0; i < files.size(); i++)
{
cout << files->getFileName(); << Error here
}
}
};
I've tried setting this function up a few different ways but I can't seem to get the right kind of code to make it work.
I would think this would work but it's throwing me errors everytime I try and mess with the DisplayDirectoryContents() function. Does anyone have any tips that I can try to help fix this? Thanks
class File
{
string fileName;
string fileTime;
public:
string getFileTime(){return fileTime;}
string getFileName(){return fileName;}
void setFileTime(){time_t now = time(NULL);
fileTime = ctime(&now);}
void setFileName(string newFileName){fileName = newFileName;}
File(){}
File(string fName)
{
fileName = fName;
time_t now = time(NULL);
fileTime = ctime(&now);
}
void MakeFile(string fName);
void RemoveFile(string fName);
};
Upvotes: 1
Views: 4701
Reputation: 25526
The reason you cannot iterate using your original loop is because std::list
does not offer an index operator (you would need to use std::vector
instead).
Alternative approach to the range based for loop (which I'd prefer, though, unless you have specific reasons not to do so) – or the way to go if you have no C++11 available – is using iterators:
for(std::list<File>::iterator i = files.begin(); i != files.end(); ++i)
{
std::cout << i->getFileName();
}
With C++11, you can have for(auto i = files.begin(); ...
.
Use cases for using iterator loop even with C++11 can be comparing items with their successors:
// check for empty list first, as std::prev would fail on!)
for(auto i = files.begin(); i != std::prev(files.end()); ++i)
{
if(someCondition(*i, *std::next(i))
{
// do something else
}
}
There is already std::remove_if
for and you should prefer it (together with a lambda; but don't forget to apply erase
afterwards, see erase-remove-idiom!), so just for illustration; starting with the simpler approach:
for(auto i = files.begin(); i != files.end(); ) // no ++i (!)
{
if(condition)
{
i = files.erase(i);
// fine for std::list; with std::vector, if removing more
// than one single element, we'd move or even copy subsequent
// elements multiple times, which is quite inefficient
}
}
Improved variant (which is what std::remove_if
does as well):
auto pos = files.begin();
for(auto i = files.begin(); i != files.end(); ++i)
{
if(!condition)
// ^ (!)
{
*pos++ = std::move(*i);
}
}
// here, std::remove_if already stops, but returns pos...
files.erase(pos, files.end());
A minimal problem might remain with move or copy assignment operators not handling self-assignment correctly, which would be covered by if(!condition && i != pos)
.
Upvotes: 2
Reputation: 206607
If you are able to use C++11 or higher, you can use a range for
loop to iterate over the contents of the list.
void DisplayDirectoryContents()
{
// Get files and folders from directory
list<File> files = this->getFiles();
// Iterate over each item in the list.
// Use a reference to avoid copying of the items.
for ( File& file : files )
{
cout << file.getFileName();
}
}
Upvotes: 2