469,621 Members | 1,865 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,621 developers. It's quick & easy.

An STL vector collection of C++ interface pointers?

Hi,

I've developed a class that implements an interface definition. It looks
like this:

class IRecord {
public:
// define interface methods by pure virtual methods
// no member variables
}
class CRecord : public IRecord {
public:
// implement interface methods
}

Now, I'm creating a collection of the interface pointers using:
std::vector<IRecord*> vRecPtrs; The following code is used to create a
series of interface pointers and push them into the vector:

std::vector<IRecord*> vRecPtrs;
vRecPtrs.resize (vRecPtrs.size()+1);
vRecPtrs[vRecPtrs.size()-1] = (IRecord*) new CRecord();
// well, I do have to resize the vector to get a new position before I can
create the new interface instance in my actual case. I can't use
vector::insert, nor vector::push_back.

So I pushed 100 instances to the vector. I iterate through all of them,
calling their methods, and they turned out fine.

However, something will screw up after I call vector::erase. In a case, I
have to remove an item from the collection, say:

delete vRecPtrs[10];
vRecPtrs.erase(vRecPtrs.begin()+10);

The 10th instance will be removed successfully. But the last item
(vRecPtrs.size()-1) will no longer be a valid pointer. Accessing any methods
of the last item will result in an access violation reading crash. I checked
the the pointer value of the last item through debuggers, and it does look
like a real pointer. Its value is expected, and does look like others. But
why can't I use it anymore? Why is the last item? Should I use some "safer
vector" for pointers?

Thanks
--
He Shiming
Aug 4 '05 #1
8 4679
He Shiming wrote:
I've developed a class that implements an interface definition. It looks
like this:

class IRecord {
public:
// define interface methods by pure virtual methods
// no member variables
}
class CRecord : public IRecord {
public:
// implement interface methods
}

Now, I'm creating a collection of the interface pointers using:
std::vector<IRecord*> vRecPtrs; The following code is used to create a
series of interface pointers and push them into the vector:

std::vector<IRecord*> vRecPtrs;
vRecPtrs.resize (vRecPtrs.size()+1);
Here you essentially say

vRecPtrs.resize(1);

because the size is 0 when a vector is default-initialised.
vRecPtrs[vRecPtrs.size()-1] = (IRecord*) new CRecord();
There is no need to cast it. There is an implicit conversion from
a pointer to CRecord to a pointer to IRecord. Try to get into habit
of _avoiding_ C-style casts at all costs (pun intended).
// well, I do have to resize the vector to get a new position before I can
create the new interface instance in my actual case. I can't use
vector::insert, nor vector::push_back.
Why can't you?
So I pushed 100 instances to the vector. I iterate through all of them,
calling their methods, and they turned out fine.

However, something will screw up after I call vector::erase. In a case, I
have to remove an item from the collection, say:

delete vRecPtrs[10];
vRecPtrs.erase(vRecPtrs.begin()+10);

The 10th instance will be removed successfully. But the last item
(vRecPtrs.size()-1) will no longer be a valid pointer.
What does that mean?
Accessing any methods
of the last item will result in an access violation reading crash.
Are you hanging onto a reference to that element in the vector?
I checked
the the pointer value of the last item through debuggers, and it does look
like a real pointer. Its value is expected, and does look like others. But
why can't I use it anymore? Why is the last item? Should I use some "safer
vector" for pointers?


No. You need to realise that if you remove something from a vector, all
iterators and references to the elements at and after that position in the
vector become _invalid_.

I am guessing here, of course. If you need real help from this newsgroup,
post your real code.

V
Aug 4 '05 #2

"He Shiming" <mailbill(NOSPAM)@21cn.com.nospam> wrote in message
news:dc**********@news.yaako.com...
Hi,

I've developed a class that implements an interface definition. It looks
like this:

class IRecord {
public:
// define interface methods by pure virtual methods
// no member variables
}
class CRecord : public IRecord {
public:
// implement interface methods
}

Now, I'm creating a collection of the interface pointers using:
std::vector<IRecord*> vRecPtrs; The following code is used to create a
series of interface pointers and push them into the vector:

std::vector<IRecord*> vRecPtrs;
vRecPtrs.resize (vRecPtrs.size()+1);
vRecPtrs[vRecPtrs.size()-1] = (IRecord*) new CRecord();
// well, I do have to resize the vector to get a new position before I can
create the new interface instance in my actual case. I can't use
vector::insert, nor vector::push_back.

So I pushed 100 instances to the vector. I iterate through all of them,
calling their methods, and they turned out fine.

However, something will screw up after I call vector::erase. In a case, I
have to remove an item from the collection, say:

delete vRecPtrs[10];
vRecPtrs.erase(vRecPtrs.begin()+10);

The 10th instance will be removed successfully. But the last item
(vRecPtrs.size()-1) will no longer be a valid pointer. Accessing any
methods of the last item will result in an access violation reading crash.
I checked the the pointer value of the last item through debuggers, and it
does look like a real pointer. Its value is expected, and does look like
others. But why can't I use it anymore? Why is the last item? Should I use
some "safer vector" for pointers?


The object type is not the issue, but the fact that when you 'erase'
an elements from a vector, any iterators pointing to it or any elements
after it (i.e. with higher subscripts), become invalid. This is the way
vectors work. One container type you might consider is a 'std::list',
which when an element is erased, only any iterators pointing to the erased
element will be invalidated, any others will remain valid. Otherwise if you
insist upon staying with the vector, you'll need to devise some way of
restoring
any iterators invalidated by an erase operation.

Book recommendation: www.josuttis.com/libbook

-Mike
Aug 4 '05 #3
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:z%******************@newsread1.mlpsca01.us.to .verio.net...
He Shiming wrote:
I've developed a class that implements an interface definition. It looks
like this:

class IRecord {
public:
// define interface methods by pure virtual methods
// no member variables
}
class CRecord : public IRecord {
public:
// implement interface methods
}

Now, I'm creating a collection of the interface pointers using:
std::vector<IRecord*> vRecPtrs; The following code is used to create a
series of interface pointers and push them into the vector:

std::vector<IRecord*> vRecPtrs;
vRecPtrs.resize (vRecPtrs.size()+1);


Here you essentially say

vRecPtrs.resize(1);

because the size is 0 when a vector is default-initialised.
vRecPtrs[vRecPtrs.size()-1] = (IRecord*) new CRecord();


There is no need to cast it. There is an implicit conversion from
a pointer to CRecord to a pointer to IRecord. Try to get into habit
of _avoiding_ C-style casts at all costs (pun intended).
// well, I do have to resize the vector to get a new position before I
can create the new interface instance in my actual case. I can't use
vector::insert, nor vector::push_back.


Why can't you?
So I pushed 100 instances to the vector. I iterate through all of them,
calling their methods, and they turned out fine.

However, something will screw up after I call vector::erase. In a case, I
have to remove an item from the collection, say:

delete vRecPtrs[10];
vRecPtrs.erase(vRecPtrs.begin()+10);

The 10th instance will be removed successfully. But the last item
(vRecPtrs.size()-1) will no longer be a valid pointer.


What does that mean?
Accessing any methods
of the last item will result in an access violation reading crash.


Are you hanging onto a reference to that element in the vector?
I checked
the the pointer value of the last item through debuggers, and it does
look like a real pointer. Its value is expected, and does look like
others. But why can't I use it anymore? Why is the last item? Should I
use some "safer vector" for pointers?


No. You need to realise that if you remove something from a vector, all
iterators and references to the elements at and after that position in the
vector become _invalid_.

I am guessing here, of course. If you need real help from this newsgroup,
post your real code.

V


I'm not referencing the old index of the elements of course.

I wouldn't call this fake code. The real code is as long as 5000 lines, and
I'm trying to simplify the problem.
Regards,
He Shiming
Aug 4 '05 #4
"Mike Wahler" <mk******@mkwahler.net> wrote in message
news:N2***************@newsread2.news.pas.earthlin k.net...

The object type is not the issue, but the fact that when you 'erase'
an elements from a vector, any iterators pointing to it or any elements
after it (i.e. with higher subscripts), become invalid. This is the way
vectors work. One container type you might consider is a 'std::list',
which when an element is erased, only any iterators pointing to the erased
element will be invalidated, any others will remain valid. Otherwise if
you
insist upon staying with the vector, you'll need to devise some way of
restoring
any iterators invalidated by an erase operation.

Book recommendation: www.josuttis.com/libbook

-Mike


I want random access to the contained elements. I would prefer using
vectors. However, I don't understand why iterators are preventing it from
working considering I'm not using any. It works like this:

vRecPtrs[99]->Method(); // vRecPtrs has 100 elements, and this call worked.
vRecPtrs.erase(vRecPtrs.begin()+10);
vRecPtrs[98]->Method(); // this one caused a crash.

Why is that related the iterators? Aren't the pointers the only thing I'm
keeping in this container?

Plus, if like you said, all iterators after it are being invalidated, why
only the last item didn't work?
Best regards,
He Shiming
Aug 4 '05 #5
He Shiming wrote:
[...]
I'm not referencing the old index of the elements of course.
If you're not using the index (old or new), then how you access the
elements?
I wouldn't call this fake code. The real code is as long as 5000 lines, and
I'm trying to simplify the problem.


Well, once you get it down to 100 lines, and still haven't found the cause
of your troubles, post it here _in_full_.

V
Aug 4 '05 #6
He Shiming wrote:
[...]
I want random access to the contained elements. I would prefer using
vectors. However, I don't understand why iterators are preventing it from
working considering I'm not using any. It works like this:

vRecPtrs[99]->Method(); // vRecPtrs has 100 elements, and this call worked.
vRecPtrs.erase(vRecPtrs.begin()+10);
vRecPtrs[98]->Method(); // this one caused a crash.
REALLY? The problem is not in the vector, then. It's somewhere else.
Why is that related the iterators? Aren't the pointers the only thing I'm
keeping in this container?
It doesn't seem related to the iterators.
Plus, if like you said, all iterators after it are being invalidated, why
only the last item didn't work?


There is no explanation. Can you trap the "crash" in the debugger and see
what causes it?

V
Aug 4 '05 #7
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:jv*******************@newsread1.mlpsca01.us.t o.verio.net...
He Shiming wrote:
[...]
I'm not referencing the old index of the elements of course.


If you're not using the index (old or new), then how you access the
elements?
I wouldn't call this fake code. The real code is as long as 5000 lines,
and I'm trying to simplify the problem.


Well, once you get it down to 100 lines, and still haven't found the cause
of your troubles, post it here _in_full_.

V


Okay I'll try.

Aug 4 '05 #8
"He Shiming" <mailbill(NOSPAM)@21cn.com.nospam> wrote in message
news:dc**********@news.yaako.com...


Well, I hate to say this but I have solve the problem in the code deduction
process. It turned out that it wasn't the fault of vector or pointers. It's
the smart pointer mechanism I'm using, which isn't covered in the content of
my question. Sorry for that.

Best regards,
He Shiming
Aug 4 '05 #9

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

20 posts views Thread by Hanzo | last post: by
9 posts views Thread by luigi | last post: by
11 posts views Thread by ma740988 | last post: by
34 posts views Thread by Adam Hartshorne | last post: by
8 posts views Thread by Ross A. Finlayson | last post: by
9 posts views Thread by Timothee Groleau | last post: by
5 posts views Thread by Gert Van den Eynde | last post: by
6 posts views Thread by lokchan | last post: by
4 posts views Thread by Christian Schmidt | last post: by
reply views Thread by devrayhaan | last post: by
reply views Thread by gheharukoh7 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.