returning a const vector

C

cpisz

At least that is what I think I want to do.

What is the proper way for me to return multiple data member objects
from an accessor method in my class while ensuring the data does not
get changed, but allowing iteration through the data?

I tryed returning a const vector but the compiler does not like the
idea of my using an iterator to look through the vector down the
road...I assume because an iterator acts like a pointer and allows you
to change the data?

Thanks,
Christopher

Here is my class currently:

#include <direct.h>
#include <winsock2.h>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

//------------------------------------------
class Directory
{
public:

Directory(){}
~Directory(){}

// Accessors
string & GetPath()
{
return m_path;
}

vector<Directory> & GetSubdirectories()
{
return m_subdirectories;
}

vector<string> & GetFilenames()
{
return m_filenames;
}

// Mutators

//--------------------------------
// Gather file and subdirectory info from the directory specified by
path
// Note: (recursive)
bool Set(const char * path)
{
// Make sure the path points to a valid directory
HANDLE file_handle = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA file_data;
DWORD error;

// Add the wild card character to the path to search it's
contents
string search_path(path);
search_path += "\\*";

// Search for the first file or directory in the path
file_handle = FindFirstFile(search_path.c_str(), &file_data);

// Was the supplied path a valid directory? (there would at least
be a "." or ".." found)
if(file_handle == INVALID_HANDLE_VALUE ||
!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
{
cout << path << "\n is an invalid directory. Error:" <<
GetLastError() <<endl;
FindClose(file_handle);
return false;
}
else
{
// Set this directory object's path to the supplied path
m_path = path;

// Do the following until no more files or directories are
found
do
{
// Skip the . and .. directories
if( strcmp(file_data.cFileName,".") != 0 &&
strcmp(file_data.cFileName,"..") != 0 )
{
// Check if we found a file or a directory
if(file_data.dwFileAttributes &
FILE_ATTRIBUTE_DIRECTORY)
{
// Get the path to the subdirectory
Directory subdirectory;
string subdir_path(path);
subdir_path += "\\";
subdir_path += file_data.cFileName;

// Read the subdirectory's contents
subdirectory.Set(subdir_path.c_str());

// Insert the record
m_subdirectories.push_back(subdirectory);
}

// Otherwise, we found a file
else
{
// Get the filename
string filename(file_data.cFileName);

// Insert the record
m_filenames.push_back(filename);
}
}
}while(FindNextFile(file_handle, &file_data) != 0);
}

// Release the file handle
FindClose(file_handle);

return false;
}

private:

// Data
string m_path;
vector<Directory> m_subdirectories;
vector<string> m_filenames;
};
 
J

John Carson

At least that is what I think I want to do.

What is the proper way for me to return multiple data member objects
from an accessor method in my class while ensuring the data does not
get changed, but allowing iteration through the data?

I tryed returning a const vector but the compiler does not like the
idea of my using an iterator to look through the vector down the
road...I assume because an iterator acts like a pointer and allows you
to change the data?

Use const_iterator rather than iterator.
 
C

cpisz

I get this error mesage when trying to use a const_iterator

144 C:\Documents and Settings\pisz_chris\My
Documents\projects\vidparser\main.cpp passing `const Directory' as
`this' argument of `const std::string& Directory::GetPath()' discards
qualifiers

on this block

cout << "Subdirectories:\n";
for( vector<Directory>::const_iterator it =
root_dir.GetSubdirectories().begin(); it !=
root_dir.GetSubdirectories().end(); it++)
{
cout << it->GetPath() <<endl;
}
 
J

John Dibling

At least that is what I think I want to do. [snip]
vector<string> & GetFilenames()
{
return m_filenames;
}

I usually prefer to do this in a more STL-ish way. Something along the
lines of this psudocode:

template<class OutputIterator>
void Directory::GetFilenames(OutputIterator itX)
const
{
std::copy(m_filenames.begin(), m_filenames.end(), itX);
}

There are some benefits to this approach, I think. For one thing, the
signature of GetFilenames() isn't dependant on Directory's
implementation details. Therefore, clients of Diretory also aren't
dependant on Directory's implementation details -- at least,
GetFilenames() isn't a culprit here. In this case, you could change
the type of m_filenames from vector to list for example, and the
signature of GetFilenames() still needn't change.

For another, GetFilenames() imposes fewer restrictions on clients than
if it returned some sort of reference to a container. 'itX' can be
anything that is valid as an OutputIterator. It could be a
back_insert_iterator, or even just a pointer to a fixed-size C-style
array. The choice is on the client.

For yet another, this method is very easy to extend. Consider if you
chose to extend your method by adding an optional paramater that
specified wildcards. Then your function could retuyrn only those
filenames that pattern-match the wildcard. If the method is
implemented as I have above, it could simply be extended by using
'copy_if()'* instead of 'copy()'. If you implement it by returning a
reference to a vector or something like that, it might be impossible or
at least very difficult to implement.

This is also a very easy method to implement. I find that when a piece
of code is harder to write than it seems like it should be, its very
often becasue my design is wrong -- I'm trying to write a bad piece of
code. If the design is 'right', the code can practically write itself.

Take care,

John Dibling

* : regarding copy_if(). There isn't one as defined in the Standard,
but this is a very easy and useful thing to implement. See Scott
Meyers' "Effective STL" item # 36 for one implementation, or "Extending
the STL" in the February 2005 C/C++ User's Journal for another.
 
?

=?ISO-8859-1?Q?Daniel_Sch=FCle?=

I get this error mesage when trying to use a const_iterator

144 C:\Documents and Settings\pisz_chris\My
Documents\projects\vidparser\main.cpp passing `const Directory' as
`this' argument of `const std::string& Directory::GetPath()' discards
qualifiers

on this block

cout << "Subdirectories:\n";
for( vector<Directory>::const_iterator it =
root_dir.GetSubdirectories().begin(); it !=
root_dir.GetSubdirectories().end(); it++)
{
cout << it->GetPath() <<endl;
}

// Accessors
const string & GetPath()const
{
return m_path;
}

one can call only const methods on a const object
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,058
Latest member
QQXCharlot

Latest Threads

Top