noobs and pointers

R

Randy

Hi,

I am a noob. I am trying to store Student objects pointers, in a
vector, within a School object.
I call a setter function to add the pointer. If I use this method it
works,
Student st = Student("Randy");
Student * stp = & st;
sc.addStudent(stp);

My problem is passing a Student to the School function. I have an
overridden function. I try to create a pointer from the passed
Student. I bet that's my problem because it's a copy ?

This all came about because I want to have a more succinct method for
doing this, just like the big kids do:
Student st = Student("Randy");
Student * stp = & st;
sc.addStudent(stp);

I've read lots but am apperantly missing the point. I am referencing
the C++ Primer.


here's my output too ... 2 Bills ?? ahaha ...

Schools Constructor 1
Student Constructor2 Randy
Overload addStudent1()
Student Constructor2 Biff
Overload addStudent3()
Student Constructor2 Bill
Overload addStudent1()
*** List ***
1 Randy
3 Bill
3 Bill
*** EOF ***
Press any key to continue . . .



main.cpp
---------------------------------------------------------------------------------------

#include <cstdlib>
#include <iostream>
#include <vector>

// #include "Templates.h"
// #include "PointersAndReference.h"
#include "StudentsAndSchools.h"


using namespace std;

int main(int argc, char *argv[])
{
// mypair<int> ok(10,23); // Declare an INT class w/
construction
// ok.printValues();
// referenceTests();

School sc;
sc.setNames("Parkside");

Student st = Student("Randy");
Student * stp = & st;
sc.addStudent(stp);

sc.addStudent(Student("Biff"));

Student st1 = Student("Bill");
Student * stp1 = & st1;
sc.addStudent(stp1);


sc.getStudentNames();

system("PAUSE");
return EXIT_SUCCESS;
}

--------------- StudentsAndSchools.h
-------------------------------------------------------------

#ifndef __StudentsAndSchools__
#define __StudentsAndSchools__



using namespace std;


class School;

class Student {

private:
static int mLastId;
string mName;
int mId;
School * mSchool;

public:
Student(){
cout << "Student Constructor1" << endl;
}
Student(string n){
cout << "Student Constructor2 " << n << endl;
mName = n;
mId = ++mLastId;
}
void setName(string n);
string getName();
int getId();
};
int Student::mLastId = 0;

string Student::getName(){ return mName; };
int Student::getId(){ return mId; };

class School{

private:
string mName;
vector<Student*> mStudents;

public:
School(){
cout << "Schools Constructor 1" << endl;
}
void addStudent(Student* );
void addStudent(Student &); // overloaded
function
void addStudent(Student);

void setNames(string n);
void getStudentNames();
};

void School::setNames(string n){
mName = n;
}
void School::addStudent(Student* n){
cout << "Overload addStudent1()" << endl;
mStudents.push_back(n);
}
void School::addStudent(Student &n ){
cout << "Overload addStudent2()" << endl;
Student * s = & n;
mStudents.push_back(s);
}
void School::addStudent(Student n ){
cout << "Overload addStudent3()" << endl;
Student * s = & n;
mStudents.push_back(s);
}

void School::getStudentNames(){
cout << "*** List ***" << endl;
for(int i=0;i < mStudents.size(); i++)
{
cout << mStudents.at(i)->getId() << " " <<
mStudents.at(i)->getName()<<endl;
}
cout << "*** EOF ***" << endl;
}


#endif
 
I

Ian Collins

Randy said:
Hi,

I am a noob. I am trying to store Student objects pointers, in a
vector, within a School object.
I call a setter function to add the pointer. If I use this method it
works,
Student st = Student("Randy");
Student * stp = & st;
sc.addStudent(stp);

My problem is passing a Student to the School function. I have an
overridden function. I try to create a pointer from the passed
Student. I bet that's my problem because it's a copy ?
Why not keep it simple and just use one addStudent member?
main.cpp
---------------------------------------------------------------------------------------

#include <cstdlib>
#include <iostream>
#include <vector>

// #include "Templates.h"
// #include "PointersAndReference.h"
#include "StudentsAndSchools.h"


using namespace std;
You don't use anything from std::
int main(int argc, char *argv[])
{
// mypair<int> ok(10,23); // Declare an INT class w/
construction
// ok.printValues();
// referenceTests();

School sc;
sc.setNames("Parkside");

Student st = Student("Randy");
Student * stp = & st;
sc.addStudent(stp);

sc.addStudent(Student("Biff"));

Student st1 = Student("Bill");
Student * stp1 = & st1;
sc.addStudent(stp1);


sc.getStudentNames();

system("PAUSE");
return EXIT_SUCCESS;
}

--------------- StudentsAndSchools.h
Don't use guards with leading double underscores, they are reserved.
using namespace std;
Never ever put a using directive in a header! It will apply in any file
that includes the header.
class School;

class Student {

private:
static int mLastId;
string mName;
int mId;
School * mSchool;

public:
Student(){
cout << "Student Constructor1" << endl;
}
Student(string n){
cout << "Student Constructor2 " << n << endl;
mName = n;
mId = ++mLastId;
}
void setName(string n);
string getName();
int getId();
};
int Student::mLastId = 0;

string Student::getName(){ return mName; };
int Student::getId(){ return mId; };
These will have to be declared "inline", or placed in a source file.
class School{

private:
string mName;
vector<Student*> mStudents;

public:
School(){
cout << "Schools Constructor 1" << endl;
}
void addStudent(Student* );
void addStudent(Student &); // overloaded
function

Silly comment!
void addStudent(Student);
You don't want this one, it is ambiguous.
 
S

Salt_Peter

Hi,

I am a noob. I am trying to store Student objects pointers, in a
vector, within a School object.

In my opinion, you should be storing Students, not pointers to
Students.
I call a setter function to add the pointer. If I use this method it
works,
Student st = Student("Randy");
Student * stp = & st;
sc.addStudent(stp);

My problem is passing a Student to the School function. I have an
overridden function. I try to create a pointer from the passed
Student. I bet that's my problem because it's a copy ?

Its a copy alright, a copy of a pointer actually, unfortuanately -
copying pointers does not copy its pointee. And having a pointer to an
object does not guarentee that the object continues to exist.

This may sound a little strange to you right now but its fundamental
in C++. A dumb pointer is just a dumb pointer.
This all came about because I want to have a more succinct method for
doing this, just like the big kids do:
Student st = Student("Randy");
Student * stp = & st;
sc.addStudent(stp);

I've read lots but am apperantly missing the point. I am referencing
the C++ Primer.

here's my output too ... 2 Bills ?? ahaha ...

Schools Constructor 1
Student Constructor2 Randy
Overload addStudent1()
Student Constructor2 Biff
Overload addStudent3()

Stop right here. This should be your first clue. Take a look at that
member function:

void School::addStudent(Student n ){
cout << "Overload addStudent3()" << endl;
Student * s = & n;
mStudents.push_back(s);
}

You are storing pointers and yet parameter (Student n) ceases to exist
once the above member function terminates. Dumb pointer points to a
Student that is no longer.

The term is: dangling pointer
The result is: undefined behaviour
Student Constructor2 Bill
Overload addStudent1()
*** List ***
1 Randy
3 Bill
3 Bill
*** EOF ***
Press any key to continue . . .

main.cpp
---------------------------------------------------------------------------------------

#include <cstdlib>
#include <iostream>
#include <vector>

// #include "Templates.h"
// #include "PointersAndReference.h"
#include "StudentsAndSchools.h"

using namespace std;

int main(int argc, char *argv[])
{
// mypair<int> ok(10,23); // Declare an INT class w/
construction
// ok.printValues();
// referenceTests();

School sc;
sc.setNames("Parkside");

Student st = Student("Randy");
Student * stp = & st;
sc.addStudent(stp);

sc.addStudent(Student("Biff"));

Student st1 = Student("Bill");
Student * stp1 = & st1;
sc.addStudent(stp1);

sc.getStudentNames();

system("PAUSE");
return EXIT_SUCCESS;

}

--------------- StudentsAndSchools.h

Underscore + Capitale letter is reserved
2 Underscores + whatever is also reserved

#ifndef StudentsAndSchools_h
#define StudentsAndSchools_h

Although Student should have its own header and School ditto
using namespace std;

Using directives in a header file is a very bad idea.
class School;

class Student {

private:
static int mLastId;
string mName;
int mId;
School * mSchool;

public:
Student(){
cout << "Student Constructor1" << endl;
}
Student(string n){
cout << "Student Constructor2 " << n << endl;
mName = n;
mId = ++mLastId;
}

Initialize non-static members using an init list.

Student(std::string n) : mName(n), mId(++mLastId)
{
cout << "Student(std::string n) " << n << endl;
}

void setName(string n);

void setName(const std::string&);
string getName();

std::string getName() const;
int getId();};

int getId() const;
int Student::mLastId = 0;

string Student::getName(){ return mName; };
int Student::getId(){ return mId; };

class School{

private:
string mName;
vector<Student*> mStudents;

public:
School(){
cout << "Schools Constructor 1" << endl;
}
void addStudent(Student* );
void addStudent(Student &); // overloaded
function

// the key is the constant keyword, the only version you need is by
const reference

void add(const Student&);

// the next "overload" prevents the former from being called although
the compiler should be generating a diagnostic about a conflict (which
one of these "overloads" should it call?).
void addStudent(Student);

void setNames(string n);
void getStudentNames();

const qualifiers missing above

<snip>
 
S

Salt_Peter

In my opinion, you should be storing Students, not pointers to
Students.

Here is an example without pointers. Note the Student's copy ctor and
the effects of uncommenting the std::vector's reserve in the School's
ctor.

#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>

class Student
{
int id;
std::string name;
public:
// ctors
Student() : id(0), name()
{
std::cout << "Student()\n";
}
Student(int i, std::string n) : id(i), name(n)
{
std::cout << "Student(int i, std::string n)\n";
}
// copy ctor
Student(const Student& copy)
{
std::cout << "Student(const Student& copy)\n";
id = copy.id;
name = copy.name;
}
// friend op
friend std::eek:stream& operator<<(std::eek:stream&, const Student&);
};

std::eek:stream& operator<<(std::eek:stream& os, const Student& r)
{
os << "id: " << r.id;
os << "\tname: " << r.name;
return os << std::endl;
}

class School
{
static int lastid;
std::string name;
std::vector< Student > students;
public:
// ctor
School(std::string n) : name(n), students()
{
std::cout << "School()\n";
// students.reserve(64);
}
// member functions
void add(const std::string& s)
{
students.push_back( Student(++lastid, s) );
}
// friend op
friend std::eek:stream& operator<<(std::eek:stream&, const School&);
};

int School::lastid;

std::eek:stream& operator<<(std::eek:stream& os, const School& r)
{
os << std::string(30, '-');
os << "\nschool: " << r.name;
os << "\nstudents: " << r.lastid;
os << std::endl;
std::copy( r.students.begin(),
r.students.end(),
std::eek:stream_iterator< Student >(os) );
os << std::string(30, '-');
return os << std::endl;
}

int main ()
{
School school("The Academy");
school.add("Alfred A");
school.add("Betty B");
school.add("Carl C");

std::cout << school;
}

/*
School()
Student(int i, std::string n)
Student(const Student& copy)
Student(int i, std::string n)
Student(const Student& copy)
Student(const Student& copy)
Student(int i, std::string n)
Student(const Student& copy)
Student(const Student& copy)
Student(const Student& copy)
------------------------------
school: The Academy
students: 3
id: 1 name: Alfred A
id: 2 name: Betty B
id: 3 name: Carl C
 
R

Roland Pibinger

In my opinion, you should be storing Students, not pointers to
Students.

Students are a classic objects (in the sense of OOP) which are
characterized by identity, state and behavior. You usually do not
duplicate (copy) and assign objects and therefore make their copy
constructor and assignment operator private. std::vector<Student> is
not a viable solution.
 
R

Randy

Students are a classic objects (in the sense of OOP) which are
characterized by identity, state and behavior. You usually do not
duplicate (copy) and assign objects and therefore make their copy
constructor and assignment operator private. std::vector<Student> is
not a viable solution.


Thank you very much for sharing your time and experience. You more
than answered my questions and now I have some focused learning to do.
Randy
 
I

I V

Students are a classic objects (in the sense of OOP) which are
characterized by identity, state and behavior. You usually do not

Really? I would have thought that Randy's Student class is a classic
_value_. Their identity is defined by equivalence (I don't
think you would want to treat students with the same name, at the same
school, with the same id, as being different), and they don't really have
any behavior (the only methods the class has are accessors). Why do you
think they should be considered entities?
 
S

Salt_Peter

Students are a classic objects (in the sense of OOP) which are
characterized by identity, state and behavior. You usually do not
duplicate (copy) and assign objects and therefore make their copy
constructor and assignment operator private. std::vector<Student> is
not a viable solution.


On what basis is the solution not viable?
Are you suggesting that a Student Record is not usueable elsewhere?
Why should a program or program(s) not have a dataset that is copyable
in order to process it in whatever way it does? What makes you beleive
that a copy implies a duplicate? (its not in the proposed std::vector<
Student > solution)
For all we know, that dataset is read and stored to file.

Why further complicate a program by a std::vector< Student* > where
the Student's allocation is then given to yet another entity?
(Specially since we are dealing here with an OP that is having issues
with dangling pointers)
 
J

James Kanze

On 13 Apr 2007 20:59:52 -0700, "Salt_Peter" wrote:
Students are a classic objects (in the sense of OOP) which are
characterized by identity, state and behavior.

I don't think he's given us enough information to draw that
conclusion. It depends on the role and the responsibilities of
the class in the actual application. If all the class
represents is a specific identity, it could be given value
semantics. If it has some real behavior, then it's probably an
entity object, and identity becomes important. (And of course,
if identity is important, you block copy and assignment, as you
said.)
 
R

Roland Pibinger

Really? I would have thought that Randy's Student class is a classic
_value_. Their identity is defined by equivalence (I don't
think you would want to treat students with the same name, at the same
school, with the same id, as being different), and they don't really have
any behavior (the only methods the class has are accessors). Why do you
think they should be considered entities?

What should the following mean?

Student Ivlenin;
Student Randy = Ivlenin;
 
R

Randy

What should the following mean?

Student Ivlenin;
Student Randy = Ivlenin;


ahaha, I don't know if your post was even meant for me buuut
conceptually, that would be illogical. I am building a database. Each
school and each student is unique. The more I think about why I
assigned an id to Student, the more I wonder why, as I could have had
any other classes contain the Student pointer. Anyways, the thought is
that the Vector(dataset) is meant for the the "observing" class
Schools, a 'foreign key', if you will, not an "entity" unto itself.
Please forgive my butchery of the OO concepts and terminology, I am
learning.

To be honest, the concept of "Student Randy = Ivlenin;" is beyond me.
 
I

I V

Really? I would have thought that Randy's Student class is a classic
_value_. Their identity is defined by equivalence (I don't
[...]
What should the following mean?

Student Ivlenin;
Student Randy = Ivlenin;

That Randy and Ivlenin both contain information about the same student.

(what does int i = int(); int j = i; mean?)
 
S

Salt_Peter

What should the following mean?

Student Ivlenin;
Student Randy = Ivlenin;

In the case a collection of unique Students is indeed required,
shouldn't that requirement be maintained by the container? ie:
std::set<Student> or std::map<int/*id*/, Student>
Lets face it, using pointers and uncopyable Students will not satisfy
the requirement of unique objects in any way. What if the dataset
contains a duplicate value?

Why should a program be handicapped from copying students based on a
phobia?
Why should a program be forced to depend on unsafe, raw pointers only?
 
R

Randy

In the case a collection of unique Students is indeed required,
shouldn't that requirement be maintained by the container? ie:
std::set<Student> or std::map<int/*id*/, Student>
Lets face it, using pointers and uncopyable Students will not satisfy
the requirement of unique objects in any way. What if the dataset
contains a duplicate value?

Why should a program be handicapped from copying students based on a
phobia?
Why should a program be forced to depend on unsafe, raw pointers only?- Hide quoted text -

- Show quoted text -

Salt_Peter ! Thank you. That makes perfect sense to me now. I will
read up on std::map/set(s). Students and Schools are standalone
entities, treat them as such, within their own sets. How would you
indicate relationship? In my example, I was able to get a list of
Students per School. I am hopelessy enamoured with storing a pointers
( eg *School mCurrSchool ) because my only exposure to non-trivial C++
programs is a game engine ... lots of pointers.

I don't understand "handicapped from copying students based on a
phobia?" so I am going to also read my Vectors ;)
 
J

James Kanze

On Apr 15, 3:42 pm, (e-mail address removed) (Roland Pibinger) wrote:
In the case a collection of unique Students is indeed required,
shouldn't that requirement be maintained by the container?

A container is just that, a container. It doesn't maintain
anything, logically.
ie:
std::set<Student> or std::map<int/*id*/, Student>
Lets face it, using pointers and uncopyable Students will not satisfy
the requirement of unique objects in any way.

It means that the identity of an object cannot be lost.
What if the dataset contains a duplicate value?

Then I have an error in my program.
Why should a program be handicapped from copying students based on a
phobia?

What's the handicap? If copying an object is an error, how does
catching it at compile time rather than at execution time
constitute a handicap?
Why should a program be forced to depend on unsafe, raw pointers only?

Have you stopped beating your wife? Raw pointers are neither
more nor less safe than anything else. Used correctly, they
work well. Used incorrectly, they don't.
 
R

Roland Pibinger

ahaha, I don't know if your post was even meant for me buuut
conceptually, that would be illogical. I am building a database. Each
school and each student is unique. The more I think about why I
assigned an id to Student, the more I wonder why, as I could have had
any other classes contain the Student pointer. Anyways, the thought is
that the Vector(dataset) is meant for the the "observing" class
Schools, a 'foreign key', if you will, not an "entity" unto itself.
Please forgive my butchery of the OO concepts and terminology, I am
learning.
To be honest, the concept of "Student Randy = Ivlenin;" is beyond me.

The problem is that STL was not designed for objects, only for values
("value semantics"). You have several possibilities now. You can adapt
to the improper tool and compromise your design by making your objects
copyable pretending that everything is a value. Or you can put 'square
pegs in round holes' by using pointers where only values are expected
and work around the 'impedance mismatch'. In a professional setting
you most probably use third party containers for objects.
Contrast this situation with Java. You'd put references to your
Student objects in an ArrayList and not even think of copying or
duplicating them. In a sense the tool dictates the usage. When you
strive for good design you need to find a better suited container or
write your own.
 
D

dave_mikesell

Have you stopped beating your wife? Raw pointers are neither
more nor less safe than anything else. Used correctly, they
work well. Used incorrectly, they don't.

Could not the same be said of using auto objects? Either way it's up
to the programmer to use the idiom correctly.
 
S

Salt_Peter

A container is just that, a container. It doesn't maintain
anything, logically.


It means that the identity of an object cannot be lost.

Thats not neccessarily what you want.
example:
Student enrolls in a class, gets a record in a central school
district's repository/database.
Student takes new studies in summer school,
then enrolls in a different school in same district the next year.
Should a new identifiable record be generated each time the student
enrolls?
Its the source or repository that should be identifiable,
the Student should be copyable to facilitate processing.
Then I have an error in my program.


What's the handicap? If copying an object is an error, how does
catching it at compile time rather than at execution time
constitute a handicap?


Have you stopped beating your wife? Raw pointers are neither
more nor less safe than anything else. Used correctly, they
work well. Used incorrectly, they don't.

Its my wife that beats me, she does so often, and i can't get enough.
read the original post from the OP. He's having issues with dangling
pointers.
 
J

James Kanze

Thats not neccessarily what you want.
example:
Student enrolls in a class, gets a record in a central school
district's repository/database.
Student takes new studies in summer school,
then enrolls in a different school in same district the next year.
Should a new identifiable record be generated each time the student
enrolls?
Its the source or repository that should be identifiable,
the Student should be copyable to facilitate processing.

I don't think I follow you. Your example seems to suggest just
the opposite. Student enrols in summer school. A copy is made,
and credited with his courses. The original student object
isn't. Result, the student looses credit.

This is precisely the case where copying is NOT wanted. There
is one, and only one, object which represents the student, and
all course credits are enregistered in that object. So there's
no risk of some of them getting lost.

[...]
Its my wife that beats me, she does so often, and i can't get enough.
read the original post from the OP. He's having issues with dangling
pointers.

So pointers are unsafe, because one person is having trouble
with them. So it is better to replace pointers with multiple
copies, where updates are done to a random copy. An expression
like "depend on unsafe, raw pointers only" reflects a
preconceived notion---the question is loaded.

If "student" has an identity, and is not just a value, then
supporting copy and assignment is a guaranteed recepe for
errors. (In general, but there are a lot of exceptions, an
object which supports modification other than through assignment
probably has identity, and should not support copy or
assignment.) And most of the time, if an object has identity,
it also has an explicit lifetime, which must be managed; you
can't foster such management off to a container.
 

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,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top