Re: static vector of pointers
On Apr 20, 8:09 pm, Jia <JiaLi...@gmail.com> wrote:
On 20 Apr, 22:12, mlimber <mlim...@gmail.com> wrote:
On Apr 20, 11:21 am, Jia <JiaLi...@gmail.com> wrote:
Hi all,
I have a class foo which has a static vector of pointers of type base
class, and a static function to set this vector.
#include <iostream>
#include <vector>
using namespace std;
class super{
protected:
int a;
public:
virtual void printOut(){ cout << "super " << endl;}
};
class subA : public super{
protected:
int a_a;
public:
virtual void printOut(){ cout << "subA" << endl;}
};
class subB : public super{
protected:
int a_b;
public:
virtual void printOut(){cout << "subB" << endl;}
};
class foo {
protected:
static std::vector<super*> myList;
static std::vector<static subA> templist;
static int count;
public:
static void setMyList();
static vector<super*> getMyList();
};
std::vector<super*>foo::myList;
std::vector<subA> foo::templist;
int foo:: count = 0;
void foo::setMyList(){
subA mysubA;
templist.push_back(mysubA);
myList.push_back(&(templist[count]));
count++;
cout<< count << " time call setMyList" << endl;
}
vector<super*> foo::getMyList()
{
return myList;
}
main()
{
foo::setMyList();
foo::setMyList();
vector<super*> newList;
newList = foo::getMyList();
newList[0]->printOut();}
What I really try to achieve is to set the myList to a vector of
pointers of super type, but actually points to the derived class
objects. I use a static vector of subA to store the sub object, so
that I could use its address to initilize myList( I know this is very
ugly, but I haven't figure out other method). But my problem is that
myList is not properly set as I expected. For example, as above
program will crush as try to execute newList[0]->printOut(). I
figured out that everytime templist calls push_back, its address has
been changed ( the first time is 0x0033c10, and second time after
push_back is called, its address has been changed) so that myList
first pointer points to nowhere, but I have already defined the
templist as static. Can anyone explain this to me? I hope I explain
myself clearly.
Apparently my previous response didn't go through or has been delayed.
The fundamental problem is that templist is being resized by the
push_back, which invalidates all pointers and iterators. Try this
instead:
#include <iostream>
#include <vector>
using namespace std;
struct super
{
virtual ~super() {}
virtual void printOut()
{ cout << "super\n";}
};
struct subA : super
{
virtual void printOut()
{ cout << "subA\n"; }
};
class foo
{
vector<super*> myList;
public:
~foo()
{
for( size_t n=0; n < myList.size(); ++n )
{
delete myList[n];
}
}
void setMyList()
{
myList.push_back( new subA );
cout<< "called setMyList" << endl;
}
vector<super*> getMyList() const
{
return myList;
}
};
int main()
{
foo f;
f.setMyList();
f.setMyList();
const vector<super*> newList = f.getMyList();
for( size_t n=0; n < newList.size(); ++n )
{
newList[n]->printOut();
}
}
Cheers! --M
Thanks a lot. Your program makes much more sense than mine. Just want
to ask you a further question(sorrry if it is stupid). Does resize
means that everytime calls push_back(), the first address of memory
will change (not just adding the memory on the existing one)?
Not necessarily, but it could. It depends on whether or not there is
unused capacity in the vector where the new element could be created.
You can use the reserve member function to specify the desired
capacity (which is different from the size), and when the capacity is
exceeded on push_back, the vector will grow by doubling its capacity
and then increasing its size by one. If the capacity is not exceeded,
no growing is necessary, so iterators and pointers are not
invalidated.
BTW, a couple of other remarks about your program that were lost from
my original reply:
Returning the vector like this:
vector<super*> newList;
newList = foo::getMyList();
instead of like this:
vector<super*> newList = foo::getMyList();
will likely introduce an extra, temporary copy of the vector. The
latter makes use of the return value optimization to eliminate this
copy.
In any case, it's usually better to hide your underlying
representation via encapsulation (see
http://www.parashift.com/c++-faq-lite/classes-and-objects.html#faq-7.4),
which in this case would likely mean that you give foo a member
function to do the printing for all of its "super" objects rather than
handing out copies of the vector in which it holds them.
Note that I added a virtual destructor to super (see
http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.7).
Also, instead of using the destructor that I added to foo, you could
use a smart pointer with container-compatible copy semantics, such as
std::tr1::shared_ptr (aka boost::shared_ptr), Loki::SmartPtr (with
reference counting policies etc.), or the reference counted smart
pointer from this FAQ and those following:
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.22
I omitted this for brevity and clarity, but it's what I would use in
your shoes.
Cheers! --M