create a dynamic array of pointers with initial values of NULL

B

BobR

(e-mail address removed) wrote in message ...
Actually my QuickSort works. I had to overload operators for it to do
so, but it seems to be fine.

OK. Eliminated another 'possible'.

I'll snip most of your code below to reduce bandwith, but, I'll check it out
later.

I know. And I think the destructor is going to be a pain too. I think I
will have to loop through the array and delete each pointer to each
file.

I don't think it will be too bad. I'll show you a little 'helper' further
down.
The problem that this solves? is that I need to be able to 'loop' and
create a new object multiple times. I don't know how to do that except
with a pointer; as in
x = new file.

Also if I 'hard-coded' file x, then it would go out of scope and be
deleted at the end of the function even if I put it into a public array
would it not?

That's what I was drifting toward. A std::vector can hold objects, but then
you would definitely need a proper copy constructor (assuming you are still
using (an array of) pointers.

Umm... it did work actually. Here is the 'new' header:

OK, nothing so far requires the copy constructor or assignment. Clean.
***********************************************************
#ifndef Directory_h
class Directory{ private:
// Prevent assignment and copy-construction:
Directory( Directory const & ); // just this, don't define it.
void operator=( Directory const & );

string Name; // Name of the Directory
unsigned int NumSubDirs, NumFiles, MaxSubDirs, MaxFiles;
int Level;
File *Files; //Pointer to an array of Files

vector<File*> vFiles;

If you do it like this (different name), you can develop it in parallel with
your existing code (just an idea).
vector<Directory*> Directories; // vector to pointers to directories

Directory *Parent; // pointer to this directories parent dir

I haven't finished reviewing your code, but I don't remember seeing this
used.
Directory(Directory *Parent, string N);
Parent?


The prof is big on seeing those words though. It does make it clearer too.

So it's your(his) 'style' choice. That's fine. I'd say 'documentation', but
that
would be more typeing, and save nothing. Just so you know it.
Yup. A big nasty one. I will have to loop through and delete each File
from the array, then the array. Big pain, but I think that's the point.
;)

Here's that 'helper' I mentioned.

template<class Seq> void EmptyThis( Seq &con ){
for( class Seq::iterator i( con.begin() ); i != con.end(); ++i ){
delete *i;
*i = 0; // in case it gets called again
}
} //template said:
Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects.
// >> for( size_t i(0); i < Directories.size(); ++i ){
// >> delete Directories.at( i );
// >> }

EmptyThis( Directories );

Yeah, I know, "I can't use templates!!". Well, your stuck using 'concrete'
functions then.

void EmptyThis( std::vector<Directory*> &con ){
for( std::vector<Directory*>::iterator i( con.begin() );
i != con.end(); ++i ){
delete *i;
*i = 0; // in case it gets called again
}
} // EmptyThis( std::vector<Directory*> &)

If you put that in class, you won't need the '*i=0' since you will call it
from the destructor, and when the destructor us done the object no longer
exists.
Using the template version, and vector vFiles, you could have used it like:

EmptyThis( vFiles );
EmptyThis( Directories );

No biggie, what ever you choose to use.

How can I dynamically create actual objects though? They do go out of
scope at the end of the function don't they?

That's where the copy constructor comes into play. When you push_back(), it
makes a copy of the object. So, there's no problem when the temp disappears.

The sort for the vector however does not seem to. In fact I cannot see
it changing anything.
I added code to read a comma delimited file with a bunch of random
words in it. I use that to create directories (who wants to type all
that!) the vector sort is given at the end of each addition, I then
list the directory and the files come back out in the order they went
in.

Good. You could also use an std::istringstream to simulate input.

std::istringstream scin("word word2 morewords etc.\n anotherword\n");
std::string temp;
scin >> temp;

Your way is fine, just pointing out another option.
(would save a file open)
My suspicion is that they are sorted by the pointer, not the thing
pointed to. I am looking at that but....

Correct. I forgot for a minute (good excuse, eh.) that it was a container of
pointers. But, I did mention that 'predicate' may be needed (nice save, eh?
<G>).

That might look something like:
bool predicate(const Directory *X, const Directory *Y)
{ return ( (*X)->name < (*Y)->name); }

std::sort( Directories.begin(), Directories.end(), predicate);

[ I don't have much practice with 'predicates', so, that may need some
adjustments. <G> ]
If you want to go that way, and have trouble, just start a new thread on that
subject. Some of the experts in this NG are really good at that (predicates).
here is the new cpp file, it has changed a little to accomodate things
like automated directory addition.
********************************* [snip]

Directory::Directory(Directory *Parent, string N){

Directory *Parent?
Name = N;
NumSubDirs = 0;
NumFiles = 0;
MaxSubDirs = 5;
MaxFiles = 5;
Level = -1;
Directories.clear();
Files = new File[MaxFiles];
}

/* operator== */
bool Directory::eek:perator==(const string & D){
if(Name != D)
return false;
else
return true;
}

bool Directory::eek:perator==(const string &D){
return ( Name == D );
}


Another point, It could have been:
bool Directory::eek:perator==(const string & D){
if(Name != D)
return false; // it leaves the function.
return true;
}

bool Directory::eek:perator<(const Directory & D){
// both names are strings so this should work.
//if the Directory Name is >, then false
if(Name > D.Name)
return false;
//if the Directory Name is <, then true
if(Name < D.Name)
return true;
}

You could simplify it:

bool Directory::eek:perator<( Directory const &D ){
// both names are strings so this should work.
return ( Name < D.Name );
}

Inside the if()s, you are resolving an expression to a bool, and then
returning true or false upon the condition. Eliminate the middle man
( if() ).
//Empty()
bool Directory::Empty(){
if(NumSubDirs == 0 && NumFiles == 0)
return true;
else
return false;
}

bool Directory::Empty(){
return ( (NumSubDirs == 0) && (NumFiles == 0) );
}
// etc.
************************************************

Oh; a comment on the std:: - the teaching assistant seems to favour NOT
using std:: so that's the way I will go for now. He's got to mark it.
Best to keep it to what he likes.

Well, ya gotta kiss-up or lose the grade! The more you code, the more you'll
develop your own style. Hopefully you'll lose the bad habits, and develop
good ones after you *pass* the course.
By the way... are you independantly wealthy or just very generous with
your time?? ;)

Neither! Unemployed (due to partial disability, and staying off welfare
(anybody out there have a home freelance C++ programming job for me? <G> $1 a
kloc?)). My favorite computer games are Adventure. C++ is like playing them,
I like problem solving/puzzles.
Also; is there a way to get the system to email me if there is a reply?

I've seen things like that in GNU/Linux, but never been interested enough to
investigate. win98 is the last ms thing I'll use, If my next machine build
won't run win98, I'll go pure Debian GNU/Linux. Maybe ask on an ms NG.
[ anybody else out there hard core enough to do a Linux kernel using g++
3.x.x (4.x?) ?]
[ ...and yeah, it works.]
 
B

BobR

(e-mail address removed) wrote in message ...
Just wanted to let you know that I created a new, shorter specific
posting about sorting the vector elsewhere.

Sort a Vector of Pointers to an object, based on objects properties

It wasn't really this topic/thread even though it's still my problem.

I think that was the correct thing to do!

Yeah, I just saw that thread when I posted a reply to your other post. I even
suggested that in the post. I'll check it out now.
 
S

sandy

BobR said:
That's what I was drifting toward. A std::vector can hold objects, but then
you would definitely need a proper copy constructor (assuming you are still
using (an array of) pointers.

The copy constructor (I think) would be difficult. I'd have to be able
to copy the object (directory) and all the sub-directories in the
Vector which as directory objects, could have directory Vectors which
could have...

Oh man. My brain is going to explode!
vector<File*> vFiles;

I'd prefer to leave my files alone for now. They seem to work. It's
just that vector that's driving me nuts now.
I haven't used it yet. 'Above' my directory class is a 'FileSystem'
class. It doesn't do much right now. It has the menu that calls the
functions in Directory and it has a pointer to the root (the first
directory) and the current directory.

My theory is that as I create new directory objects I store the address
of the parent. Then when I need to do: cd.. to go up a level, from the
FileSystem class I can access the Parent address of the current
directory and re-set my FileSystem current directory to that. Then all
calls from the FileSystem will go to the new 'Current' directory which
was the parent of old 'Current' directory.

Here's that 'helper' I mentioned.

template<class Seq> void EmptyThis( Seq &con ){
for( class Seq::iterator i( con.begin() ); i != con.end(); ++i ){
delete *i;
*i = 0; // in case it gets called again
}
} //template said:
Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects.
// >> for( size_t i(0); i < Directories.size(); ++i ){
// >> delete Directories.at( i );
// >> }

EmptyThis( Directories );

Yeah, I know, "I can't use templates!!". Well, your stuck using 'concrete'
functions then.

Actually I didn't know I couldn't use templates. I would have had
problems and just figured it was me not using correct syntax. (Which I
guess it would be).
void EmptyThis( std::vector<Directory*> &con ){
for( std::vector<Directory*>::iterator i( con.begin() );
i != con.end(); ++i ){
delete *i;
*i = 0; // in case it gets called again
}
} // EmptyThis( std::vector<Directory*> &)

This doesn't do it??

Directory::~Directory()
{
//delete the array of files
delete Files;
// delete each directory pointer from the vector
for(size_t i(0) ; i < Directories.size(); ++i )
{
delete Directories.at( i );
}
}
If you put that in class, you won't need the '*i=0' since you will call it
from the destructor, and when the destructor us done the object no longer
exists.
Using the template version, and vector vFiles, you could have used it like:

EmptyThis( vFiles );
EmptyThis( Directories );

No biggie, what ever you choose to use.

How can I dynamically create actual objects though? They do go out of
scope at the end of the function don't they?

That's where the copy constructor comes into play. When you push_back(), it
makes a copy of the object. So, there's no problem when the temp disappears.

The sort for the vector however does not seem to. In fact I cannot see
it changing anything.
I added code to read a comma delimited file with a bunch of random
words in it. I use that to create directories (who wants to type all
that!) the vector sort is given at the end of each addition, I then
list the directory and the files come back out in the order they went
in.

Good. You could also use an std::istringstream to simulate input.

std::istringstream scin("word word2 morewords etc.\n anotherword\n");
std::string temp;
scin >> temp;

Your way is fine, just pointing out another option.
(would save a file open)
My suspicion is that they are sorted by the pointer, not the thing
pointed to. I am looking at that but....

Correct. I forgot for a minute (good excuse, eh.) that it was a container of
pointers. But, I did mention that 'predicate' may be needed (nice save, eh?
<G>).

That might look something like:
bool predicate(const Directory *X, const Directory *Y)
{ return ( (*X)->name < (*Y)->name); }

std::sort( Directories.begin(), Directories.end(), predicate);

[ I don't have much practice with 'predicates', so, that may need some
adjustments. <G> ]
If you want to go that way, and have trouble, just start a new thread on that
subject. Some of the experts in this NG are really good at that (predicates).

Thanks I did. I tried something that looked like what you have but got
errors... It wasn't exact though...

It was a struct.

your line: return ( (*X)->name < (*Y)->name);
I converted to this: return ( *X->GetName() < *Y->GetName());
because name is private.

It gives the error:
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

so I tried this:
return ( X->GetName() < Y->GetName());
to get this
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

and this:
return ( (*X)->GetName() < (*Y)->GetName());
which resulted in this
base operand of `->' has non-pointer type `const Directory'

I have posted it in a smaller posting in the group for that one
problem. Hopefully someone gets back to me.

bool Directory::Empty(){
return ( (NumSubDirs == 0) && (NumFiles == 0) );
}
// etc.
Bob R
POVrookie

Thanks for all your help. Believe it or not I am learning a lot from
this assignment and the pain it is causing me! ;)

I have to continue and get this thing working even if it doesn't sort
properly but if I complete the rest in time and still can't do it any
otherway I may try to convert a quick sort for the vector.

It's all about time. Due date is am Monday so I can only do what I can
do! ;)
 
B

BobR

(e-mail address removed) wrote in message ...
The copy constructor (I think) would be difficult. I'd have to be able
to copy the object (directory) and all the sub-directories in the
Vector which as directory objects, could have directory Vectors which
could have...

Oh man. My brain is going to explode!

DO NOT EXPLODE!! You'd get guts all over this beautiful NG. :-}

Keep in mind that *each instance* object of your class has only one set of
'things'. The class instance(object) is not responsible for things in another
instance (object).

Your copy-constructor won't be as complex as you think.
For one thing, std::vector has an operator=(), so:

vector<Directory*> A(10);
vector<Directory*> B;
B = A;
cout<<"A.size()="<<A.size()
<<" B.size()="<<B.size()<<endl;

// out: A.size()=10 B.size()=10

Now, your 'File *Files' is a whole other thing. You have to 'new' some more
memory, and copy to that.

When you see 'array', you need to start thinking 'vector'. A vector is so
much like an array that it is almost a drop-in-replacement (it is even
guaranteed (std) to be continuous in memory).

With arrays, you always need to pass the size into a function (or otherwise
keep track of it, like you do in your class):

void MyFunc( File *file, int size){....}

But, vectors know their size:

void MyFunc( vFiles &file{ /* file.size() */ ....}
vector<File*> vFiles;

I'd prefer to leave my files alone for now. They seem to work. It's
just that vector that's driving me nuts now.
Here's that 'helper' I mentioned.

template<class Seq> void EmptyThis( Seq &con ){
for( class Seq::iterator i( con.begin() ); i != con.end(); ++i ){
delete *i;
*i = 0; // in case it gets called again
}
} //template said:
Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects. EmptyThis( Directories );
} // Dtor
Yeah, I know, "I can't use templates!!". Well, your stuck using 'concrete'
functions then.

Actually I didn't know I couldn't use templates. I would have had
problems and just figured it was me not using correct syntax. (Which I
guess it would be).

Well, if templates are not forbidden, put that one above your class. It won't
hurt anything. A template does not create any code until you actually use it.
Easy enough to delete it (if not used) when you turn in your project.
This doesn't do it??

Yes said:
Directory::~Directory()
{
//delete the array of files
delete Files;
// delete each directory pointer from the vector
for(size_t i(0) ; i < Directories.size(); ++i )
{
delete Directories.at( i );
}
}
(predicates).

Thanks I did. I tried something that looked like what you have but got
errors... It wasn't exact though...
It was a struct.
your line: return ( (*X)->name < (*Y)->name);
I converted to this: return ( *X->GetName() < *Y->GetName());
because name is private.

It gives the error:
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

I have posted it in a smaller posting in the group for that one
problem. Hopefully someone gets back to me.

I'm sure you've seen my 'fix' in the other thread by now.
Thanks for all your help. Believe it or not I am learning a lot from
this assignment and the pain it is causing me! ;)

I once spent three days looking for a bug that turned out to be a single
missing semicolon on one line!! Boy, did I learn! <G>

Like I've said before:
"Don't chase the rainbow looking for the pot of gold, just pick up the
diamonds along the way.".
Learning C++ is one small step at a time.
I think you are doing very well.
It's all about time. Due date is am Monday so I can only do what I can
do! ;)

Well then quit shootin' the breeze with idiots like me, and get to work! <G>

Git 'er done!
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top