Store pointers in a vector?

R

Roland Bengtsson

I have a class Conception and I have this in a vector, it should be:

vector<Conception> vek; // vector
vector<Conception>::iterator vek; // iterator to vek

But what if I want to have pointers to class Conception instead? How
can I do that? And how should I write to declare an iterator to this
vector?
 
J

Jeremy Cowles

Roland Bengtsson said:
I have a class Conception and I have this in a vector, it should be:

vector<Conception> vek; // vector
vector<Conception>::iterator vek; // iterator to vek

But what if I want to have pointers to class Conception instead? How
can I do that? And how should I write to declare an iterator to this
vector?

I am just moving to C++, so this may be wrong, but isn't a pointer just a
data type like anything else? I would think you could declare it like this:

vector<Conception*> vek; // vector

No?

Jeremy
 
J

Jeffrey Schwab

Jeremy said:
I am just moving to C++, so this may be wrong, but isn't a pointer just a
data type like anything else? I would think you could declare it like this:

vector<Conception*> vek; // vector

No?

Jeremy

Right, but make sure you've declared vector, and that you're looking in
the right namespace for it:

#include <vector>

int main( )
{
std::vector<Conception*> vek; // useless comment
}
 
J

Jeffrey Schwab

Jeffrey said:
Right, but make sure you've declared vector, and that you're looking in
the right namespace for it:

#include <vector>

int main( )
{
std::vector<Conception*> vek; // useless comment

Whoops! That should be:

class Conception;
 
M

Mike Wahler

Roland Bengtsson said:
I have a class Conception and I have this in a vector, it should be:

vector<Conception> vek; // vector
vector<Conception>::iterator vek; // iterator to vek

You have the same name ('vek') for two different objects!
But what if I want to have pointers to class Conception instead?

No problem.
How
can I do that?

Same way you specify any other type element.

vector said:
And how should I write to declare an iterator to this
vector?

vector<Conception *>::iterator vi;

Of course now you're responsible for managing any memory pointed
to by your pointers.

-Mike
 
R

Roland Bengtsson

More code here may clarify!
Now I have this compiler error:
main.cpp(37) : error C2679: binary '=' : no operator defined which
takes a right-hand operand of type 'class std::list<class Conception,
class std::allocator<class Conception> >::iterator' (or there is no
acceptable conversion)

#include <iostream>
#include <vector>
#include <list>
using namespace std;

class Conception
{
public:
Conception();
virtual ~Conception();

char *name; // the classen contains more than this...
};

void ListConcept(list &ConceptList);

void main()
{
list CList;

ListConcept(CList);
}

void ListConcept(list &ConceptList)
{
// 1. Declare a list with Conception
list::iterator It_Print;
// 2. Declare a vector with pointers to Conceptions
vector SortPage(ConceptList.size());
// 3. Declare an iterator to go through nr 2.
vector::iterator it_SortPage;

// This loop fills SortPage vector with pointers to Conceptions in
// declaration 1.
for(It_Print = ConceptList.begin();It_Print !=
ConceptList.end();It_Print++)
{
*it_SortPage = It_Print; // What should be here???
it_SortPage++;
}
}
 
R

Rolf Magnus

Roland said:
More code here may clarify!
Now I have this compiler error:
main.cpp(37) : error C2679: binary '=' : no operator defined which
takes a right-hand operand of type 'class std::list<class Conception,
class std::allocator<class Conception> >::iterator' (or there is no
acceptable conversion)

#include <iostream>
#include <vector>
#include <list>
using namespace std;

class Conception
{
public:
Conception();
virtual ~Conception();

char *name; // the classen contains more than this...
};

void ListConcept(list &ConceptList);

ConceptList doesn't have a type, since list is the name of a template,
not of a type. You must specify the template parameters, like:

void ListConcept(list<Conception*> &ConceptList);

I assume you want that, since you asked how to define a container of
pointers to Conception.
void main()


main() _must_ return int. Nothing else. Never!
{
list CList;

ListConcept(CList);
}

void ListConcept(list &ConceptList)

void ListConcept(list said:
{
// 1. Declare a list with Conception
list::iterator It_Print;

list said:
// 2. Declare a vector with pointers to Conceptions
vector SortPage(ConceptList.size());

vector said:
// 3. Declare an iterator to go through nr 2.
vector::iterator it_SortPage;

vector said:
// This loop fills SortPage vector with pointers to Conceptions in
// declaration 1.
for(It_Print = ConceptList.begin();It_Print !=
ConceptList.end();It_Print++)
{
*it_SortPage = It_Print; // What should be here???

It_Print is an iterator to Concept*, *it_SortPage is a Concept*. That
doesn't match. Write:

*it_SortPage = *It_Print;
it_SortPage++;
}
}

Uhm, I assume your function actually does a bit more, because as it is
now, it copies the container and then destroys the copy without doing
anything with it. You also don't seem to modify the list, so your
function should take a const reference to it.
Btw, you could make your function a lot shorter by using std::copy from
<algorithm>:

void ListConcept(list<Concept*> &ConceptList)
{
vector<Concept*> SortPage;
SortPage.reserve(ConceptList.size());
std::copy(ConceptList.begin(), ConceptList.end(),
std::back_inserter(SortPage));

//the rest, whatever it is supposed to do
}
 
R

Roland Bengtsson

void ListConcept(list &ConceptList);
ConceptList doesn't have a type, since list is the name of a template,
not of a type. You must specify the template parameters, like:

void ListConcept(list<Conception*> &ConceptList);

I assume you want that, since you asked how to define a container of
pointers to Conception.

But the list stores not pointers to Conceptions, they store the whole
Conception

void ListConcept(list<Conception> &ConceptList)

A reference is passed to ListConcept()
main() _must_ return int. Nothing else. Never!

Ok, but I have heared that the compiler put a return 0; in the end of
main() if the type is void. And this is ansi standard now.
Uhm, I assume your function actually does a bit more, because as it is
now, it copies the container and then destroys the copy without doing
anything with it. You also don't seem to modify the list, so your
function should take a const reference to it.

No, the ListConcept() will sort Conceptions and then list them. The
ConceptList will not be modified. Is this the right prototyp if I use
const?

void ListConcept(const list said:
Btw, you could make your function a lot shorter by using std::copy from
<algorithm>:

This kind of help is always welcome, but I can't compile the code
anymore with this modifications. VC++ says:

include\xutility(19) : error C2679: binary '=' : no operator defined
which takes a right-hand operand of type 'class Conception' (or there
is no acceptable conversion)

I got an error in a standard include-file, I have not a clue what it
is...
Btw, the next step is the sorting, I have two alternatives, use a
functionpointer or a functionoperator. None of these are working:)

Here are the new code:

#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;

class Conception
{
public:
Conception(int p=0): page(p) {};

void SetPage(int t)
{
page = t;
};

int GetPage()
{
return page;
};
int page; // The class contains more, this is just a testcase
};

// This class is for the sorting
class Conceptionsorter
{
public:
// A functionoperator
int operator() (int pageA, int pageB)
{
return pageA - pageB;
};
};

void ListConcept(list<Conception> &ConceptList);

void main()
{
list<Conception> CList;
Conception A,B,C;

A.SetPage(12);
B.SetPage(7);
C.SetPage(24);

CList.push_back(A);
CList.push_back(B);
CList.push_back(C);

ListConcept(CList);
}


// a simple sort function
int Csort(int pageA, int pageB)
{
return pageA - pageB;
}

void ListConcept(list<Conception> &ConceptList)
{
// 2. Declare a vector with pointers to Conceptions
vector<Conception *> SortPage;
vector<Conception *>::iterator it_SortPage;

SortPage.reserve(ConceptList.size());
std::copy(ConceptList.begin(), ConceptList.end(),
std::back_inserter(SortPage));

// Print all data from the vector, in reality the data is in the
list
for(it_SortPage = SortPage.begin();it_SortPage !=
SortPage.end();it_SortPage++)
cout << (*it_SortPage)->GetPage() << endl;

// Sort the data, I have 2 alternatives
// 1. Give a function as argument
//sort(SortPage.begin(), SortPage.end(),Csort);

// 2. Give a functionobject as argument
//sort(SortPage.begin(), SortPage.end(),Conceptionsorter());
}
 
R

Rolf Magnus

Roland said:
But the list stores not pointers to Conceptions, they store the whole
Conception

How should I have known that from your incorrect pseudo code? Please
always post real code to avoid such misunderstandings.
void ListConcept(list<Conception> &ConceptList)

A reference is passed to ListConcept()


Ok, but I have heared that the compiler put a return 0; in the end of
main() if the type is void. And this is ansi standard now.

No. A void function doesn't return anything. The C++ standard clearly
says that main must return int. What you are probably referring to is
that you can leave out a return statement in main, which will
implicitly return 0 then. Nevertheless, the return type must still be
int. Note also that this implicit return is an exception that is only
valid for the main() function.
No, the ListConcept() will sort Conceptions and then list them. The
ConceptList will not be modified.

Ah, now I see what you want.
Is this the right prototyp if I use
const?

void ListConcept(const list<Conception> &ConceptList);
Yes.


This kind of help is always welcome, but I can't compile the code
anymore with this modifications.

Well, I was assuming that both containers are supposed to contain
pointers. If one has direct instances, and the other one has pointers,
this will of course not work.
VC++ says:

include\xutility(19) : error C2679: binary '=' : no operator defined
which takes a right-hand operand of type 'class Conception' (or there
is no acceptable conversion)

I got an error in a standard include-file, I have not a clue what it
is...

This is because the std::copy template tries to assign an instance of
type Conception to a pointer to Conecption, which is not possible. The
error message could be more clear (e.g. by telling the left hand type,
too or the line of your code that was the reason for the assignment).
Btw, the next step is the sorting, I have two alternatives, use a
functionpointer or a functionoperator. None of these are working:)

Here are the new code:

#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;

class Conception
{
public:
Conception(int p=0): page(p) {};

void SetPage(int t)
{
page = t;
};

You don't need a semicolon after a function definition.
int GetPage()
{
return page;
};
int page; // The class contains more, this is just a testcase
};

// This class is for the sorting
class Conceptionsorter
{
public:
// A functionoperator
int operator() (int pageA, int pageB)
{
return pageA - pageB;
};
};

The comparison object is expected to take two objects of the element
type of your container (i.e. pointers to Conception, not int) and
return a bool (true if the first argument is less, false if it's
greater than the other), so change it to:

class Conceptionsorter
{
public:
// A functionoperator
bool operator()(Conception* a, Conception* b) const
{
return a->GetPage() < b->GetPage();
}
};

void ListConcept(list<Conception> &ConceptList);

void main()
{
list<Conception> CList;
Conception A,B,C;

A.SetPage(12);
B.SetPage(7);
C.SetPage(24);

CList.push_back(A);
CList.push_back(B);
CList.push_back(C);

ListConcept(CList);
}


// a simple sort function
int Csort(int pageA, int pageB)
{
return pageA - pageB;
}

You'd need changes similar to those for the function object:

// a simple sort function
bool Csort(Conception* a, Conception* b)
{
void ListConcept(list<Conception> &ConceptList)
{
// 2. Declare a vector with pointers to Conceptions
vector<Conception *> SortPage;
vector<Conception *>::iterator it_SortPage;

SortPage.reserve(ConceptList.size());
std::copy(ConceptList.begin(), ConceptList.end(),
std::back_inserter(SortPage));

Well, if one container contains objects and the other one pointers to
them, you'll need either a function object that returns a pointer, or
you have to go back to copying the data yourself. I'd do it something
like this:

vector<Conception *> SortPage;
list<Conception>::iterator it = ConceptList.begin();
list<Conception>::iterator end = ConceptList.end();

SortPage.reserve(ConceptList.size());
for(; it != end; ++it)
SortPage.push_back(&(*it));

*it will be the element to which the iterator points, and then you need
to take that element's address with the & operator and append the
result to the vector.
// Print all data from the vector, in reality the data is in the
list
for(it_SortPage = SortPage.begin();it_SortPage !=
SortPage.end();it_SortPage++)
cout << (*it_SortPage)->GetPage() << endl;

// Sort the data, I have 2 alternatives
// 1. Give a function as argument
//sort(SortPage.begin(), SortPage.end(),Csort);

// 2. Give a functionobject as argument
//sort(SortPage.begin(), SortPage.end(),Conceptionsorter());


Those sort() calls should work with the above modifications.
 
A

Anders Hybertz

Roland said:
I have a class Conception and I have this in a vector, it should be:

vector<Conception> vek; // vector
vector<Conception>::iterator vek; // iterator to vek

But what if I want to have pointers to class Conception instead? How
can I do that? And how should I write to declare an iterator to this
vector?

The solution might be for you as some other suggest to just just object
pointers, but that opens up a new can of worms.

"Who manages the lifetime of the objects in the vector."

If the aggregated vector goes out of scope your constructor might want
to delete all the object in the vector. Other objects might now have
dangling pointers to objects that has been deleted.

Instead have a look at boost and it's shared pointer implementation. It
introduces reference counted objects, and ensures that you never get
another dangling pointer. And you don't have to worry about destruction
either :)

The syntax is like

typedef boost::shared_ptr<Conception> ConceptionPtr;
std::vector<ConceptionPtr> ConceptionVector;

// Put new elements in vector
ConceptionVector.push_back( ConceptionPtr( new Conception(...) );

// Use elements in vector
ConceptionVector[42]->ConceptionMemberFunction(...);


// NOTE: Don't worry about destruction. On end of scope, the shared
pointer will call the destructors on all objects that have a ref. count = 0

Hope that helps

/Anders
 
R

Roland Bengtsson

Btw I didn't get the copy function to compile for me. I suspect that
it try to copy the whole conception in the ConceptList instead of
pointers?
 
R

Roland Bengtsson

Anders Hybertz said:
The solution might be for you as some other suggest to just just object
pointers, but that opens up a new can of worms.

"Who manages the lifetime of the objects in the vector."

If the aggregated vector goes out of scope your constructor might want
to delete all the object in the vector. Other objects might now have
dangling pointers to objects that has been deleted.

Instead have a look at boost and it's shared pointer implementation. It
introduces reference counted objects, and ensures that you never get
another dangling pointer. And you don't have to worry about destruction
either :)

The syntax is like

typedef boost::shared_ptr<Conception> ConceptionPtr;

Hi, I got this error when typing the line above in my program. I have
never heard of boost, is this a keyword in C++?

main.cpp(37) : error C2653: 'boost' : is not a class or namespace name

Anyway I don't think it's a problem with bad pointers in my case
because I use the vector with pointers as a local variable. When the
function is ended the vector with the pointers is also automatically
deleted. But I think you had a good point there to be careful about.

/Roland
 
R

Rob Williscroft

Roland Bengtsson wrote in
Hi, I got this error when typing the line above in my program. I have
never heard of boost, is this a keyword in C++?

main.cpp(37) : error C2653: 'boost' : is not a class or namespace name

Boost is a set of C++ libraries goto http://www.boost.org

boost::shared_ptr docs are at:

http://www.boost.org/libs/smart_ptr/shared_ptr.htm

Unfortunatly the download is between 5 and 10 MB depending on the
archive format you choose, and there is no option to just get only
the library you want (in this case shared_ptr).

Rob.
 
R

Rolf Magnus

Roland said:
Btw I didn't get the copy function to compile for me. I suspect that
it try to copy the whole conception in the ConceptList instead of
pointers?

Read my answer to your other posting.
 

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,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top