How do I call a method of an object which is stored within a vector? The following code fails...
ClassA* class_derived_a = new ClassDerivedA;
ClassA* class_another_a = new ClassAnotherDerivedA;
vector<ClassA*> test_vector;
test_vector.push_back(class_derived_a);
test_vector.push_back(class_another_a);
for (vector<ClassA*>::iterator it = test_vector.begin(); it != test_vector.end(); it++)
it->printOutput();
The code retrieves the following error:
test3.cpp:47: error: request for
member ‘printOutput’ in ‘*
it.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator-> with _Iterator = ClassA**, _Container = std::vector >’, which
is of non-class type ‘ClassA*’
The problem seems to be it->printOutput(); but at the moment I don't know how to call the method properly, does anyone know?
regards mikey
The things in the vector are pointers. You need:
(*it)->printOutput();
which dereferences the iterator to get the pointer from the vector, then uses -> on the pointer to call the function. The syntax you show in your question would work if the vector contained objects rather than pointers, in which case the iterator acts like a pointer to one of those objects.
There is a Boost.PointerContainer library which could help you tremendously here.
First: it takes care of memory management, so you won't forget the release the memory pointed to.
Second: it provides a "dereferenced" interface so that you can use the iterators without the ugly patching (*it)->.
#include <boost/ptr_container/ptr_vector.hpp>
int main(int argc, char* argv[])
{
boost::ptr_vector<ClassA> vec;
vec.push_back(new DerivedA());
for (boost::ptr_vector<ClassA>::const_iterator it = vec.begin(), end = vec.end();
it != end; ++it)
it->printOutput();
}
From a Dependency Injection point of view, you might be willing to have printOutput takes a std::ostream& parameter so that you can direct it to whatever stream you want (it could perfectly default to std::cout)
Related
I have vector
std::vector<OrderInfo *> vec
and a queue
queue<OrderInfo *> *myQueue = new queue<OrderInfo *>;
I want to copy the vector into the queue. I tried using How can I copy an entire vector into a queue? this answer and also this Insert into an STL queue using std::copy
but it's not working, how do I make it work?
this is what I tried:
myQueue = new queue(vec.begin(), vec.end());
i got
error: no matching function for call to
‘std::queue::queue(std::vector::iterator,
std::vector::iterator)’ myQueue = new
queue(vec.begin(), vec.end());
and when I tried this:
std::copy(vec.begin(),vec.end(),std::back_inserter(myQueue));
i got:
required from
‘BacStrategy::BacStrategy(EZXConnectionHandler&, const
string&, bool, const double&, int) [with Event_Type =
EZXOrderEventHandler; std::__cxx11::string =
std::__cxx11::basic_string]’
/home/yaodav/Desktop/git_repo/test/main.cpp:324:51: required from
here /usr/local/include/c++/7.4.0/bits/stl_iterator.h:490:7: error:
‘std::queue*’ is not a class, struct, or union type
operator=(const typename _Container::value_type& __value)
myQueue is a pointer, not a queue, and can’t be passed to std::back_inserter. To fix this, don’t declare it as a pointer.
Furthermore, std::back_inserter can’t be used with a std::queue, as the second link you posted explains.
Instead, simply write
std::queue<OrderInfo*> myQueue{
std::deque<OrderInfo*>(vec.begin(), vec.end())
};
If you really need a pointer, adapt the code as follows:
std::queue<OrderInfo*>* myQueue = new std::queue<OrderInfo*>{
std::deque<OrderInfo*>(vec.begin(), vec.end())
};
Lastly, if you need to fill an already initialised queue, proceed as follows: create a temporary queue using the above and assign it to your pointer:
*myQueue = std::queue<OrderInfo*>{std::deque<OrderInfo*>(vec.begin(), vec.end())};
If this looks too messy you can also create a temporary variable for that queue — but in that case you need to use std::move to ensure that the queue gets move-assigned, not expensively copied:
auto tmp = std::queue<OrderInfo*>{std::deque<OrderInfo*>(vec.begin(), vec.end())};
*myQueue = std::move(tmp);
In the same vein, consider carefully whether you want to store OrderInfos rather than pointers to OrderInfos.
Well I am creating a vector like this
vector<Member*> emp;
Then I am creating heap objects of the member class like this
Member* memObj = new Member();
Then using push_back like this
emp.push_back(memObj);
Well after using all my functions do I have to clear the memory by iterating like this ?
for( vector<Member*>::iterator iter = emp.begin();
iter != emp.end(); )
{
Member* mem = *iter;
iter = emp.erase (iter);
delete mem;
//iter++;
}
Is there any effective way other than iterating through each value? clear function calls the destructor only and it clears the values but does not free the memory..I wish to achieve polymorphism here...I am new in C++ ....please help..Thanks in advance.. :) I am not using C++11
If you are able to use a C++11 compiler, you can use one of the smart pointers.
std::unique_ptr
std::vector<std::unique_ptr<Member>> emp;
or
std::shared_ptr
std::vector<std::shared_ptr<Member>> emp;
EDIT
If you are not able to use a C++11 compiler, VS 2005 is definitely too old to support C++11, you will have to delete the objects manually, like you have shown.
However, I would add a helper class to help with deleteing the Member objects.
struct MemberDeleteHelper
{
MemberDeleteHelper(std::vector<Member*> emp) : emp_(emp);
~MemberDeleteHelper()
{
for( vector<Member*>::iterator iter = emp.begin();
iter != emp.end(); ++iter )
{
delete *iter;
}
}
std::vector<Member*>& emp_;
};
and use it as:
vector<Member*> emp;
MemberDeleteHelper deleteHelper(emp);
With this in place, the elements of emp will be deleted no matter how you return from the function. If an exception gets thrown from a nested function call, the stack will be unrolled and the elements of emp will still be deleted.
EDIT 2
Do not use auto_ptr objects in std::vector. The pitfalls of using auto_ptr in STL containers are discussed at http://www.devx.com/tips/Tip/13606 (Thanks are due to #pstrjds for the link).
Unless your intent is to added instances of types derived from Member to the vector, there's no need for vector<Member*>, just use vector<Member>.
If you actually need dynamic allocation, use vector<unique_ptr<Member>>. The smart pointer will automatically delete the instances when you clear() the vector. If this is the case, don't forget that Member needs a virtual destructor.
Similar options for pre-C++11 compilers are std::vector<std::tr1::shared_ptr<Member>> or boost::ptr_vector<Member>.
Finally, your current code has a bug. vector::erase returns a pointer to the next element, so by manually incrementing the iterator within the loop, you're skipping every other element. And I don't understand why you're going through the trouble of storing the pointer in a temporary variable. Your loop should be
for( vector<Member*>::iterator iter = emp.begin(); iter != emp.end(); )
{
delete *iter;
iter = emp.erase(iter);
}
or just delete all the elements first and then clear the vector
for( vector<Member*>::iterator iter = emp.begin(); iter != emp.end(); ++iter)
{
delete *iter;
}
emp.clear();
I guess I don't fully understand how destructors work in C++. Here is the sample program I wrote to recreate the issue:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
struct Odp
{
int id;
Odp(int id)
{
this->id = id;
}
~Odp()
{
cout << "Destructing Odp " << id << endl;
}
};
typedef vector<shared_ptr<Odp>> OdpVec;
bool findOdpWithID(int id, shared_ptr<Odp> shpoutOdp, OdpVec& vec)
{
shpoutOdp.reset();
for (OdpVec::iterator iter = vec.begin(); iter < vec.end(); iter++)
{
Odp& odp = *(iter->get());
if (odp.id == id)
{
shpoutOdp.reset(iter->get());
return true;
}
}
return false;
}
int main()
{
OdpVec vec;
vec.push_back(shared_ptr<Odp>(new Odp(0)));
vec.push_back(shared_ptr<Odp>(new Odp(1)));
vec.push_back(shared_ptr<Odp>(new Odp(2)));
shared_ptr<Odp> shOdp;
bool found = findOdpWithID(0, shOdp, vec);
found = findOdpWithID(1, shOdp, vec);
}
Just before main() concludes, the output of this program is:
Destructing Odp 0
Destructing Odp 1
Why does this happen? I'm retaining a reference to each of the Odp instances within the vector. Does it have something to do with passing a shared_ptr by reference?
UPDATE I thought that shared_ptr::reset decremented the ref count, based on MSDN:
The operators all decrement the
reference count for the resource
currently owned by *this
but perhaps I'm misunderstanding it?
UPDATE 2: Looks like this version of findOdpWithID() doesn't cause the destructor to be called:
bool findOdpWithID(int id, shared_ptr<Odp> shpoutOdp, OdpVec& vec)
{
for (OdpVec::iterator iter = vec.begin(); iter < vec.end(); iter++)
{
Odp& odp = *(iter->get());
if (odp.id == id)
{
shpoutOdp = *iter;
return true;
}
}
return false;
}
This line right here is probably what is tripping you up.
shpoutOdp.reset(iter->get());
What you're doing here is getting (through get()) the naked pointer from the smart pointer, which won't have any reference tracking information on it, then telling shpoutOdp to reset itself to point at the naked pointer. When shpoutOdp gets destructed, it's not aware that there is another shared_ptr that points to the same thing, and shpoutOdp proceeds to destroy the thing it's pointed to.
You should just do
shpoutOdp = *iter;
which will maintain the reference count properly. As an aside, reset() does decrement the reference counter (and only destroys if the count hits 0).
So many things that are being used nearly correctly:
bool findOdpWithID(int id, shared_ptr<Odp> shpoutOdp, OdpVec& vec)
Here the parameter shpoutOdp is a a copy of the input parameter. Not such a big deal considering it is a shared pointer but that is probably not what you were intending. You probably wanted to pass by reference otherwise why pass it to the function in the first place.
shpoutOdp.reset();
Resetting a parameter as it is passed in.
Does this mean it could be dirty (then why have it as an input parameter) it make the function return a shared pointer as a result if you want to pass something out.
Odp& odp = *(iter->get());
Don't use get on shared pointers unless you really need to (and you really if ever need too). Extracting the pointer is not necessary to get at what the pointer points at and makes you more likely to make mistakes because you are handling pointers. The equivalent safe(r) line is:
Odp& odp = *(*iter); // The first * gets a reference to the shared pointer.
// The second star gets a reference to what the shared
//pointer is pointing at
This is where it all goes wrong:
shpoutOdp.reset(iter->get());
You are creating a new shared pointer from a pointer. Unfortunately the pointer is already being managed by another shared pointer. So now you have two shared pointers that think they own the pointer and are going to delete it when they go out of scope (the first one goes out of scope at the end of the function as it is a copy of the input parameter (rather than a reference)). The correct thing to do is just to do an assignment. Then the shared pointers know they are sharing a pointer:
shpoutOdp = *iter; // * converts the iterator into a shared pointer reference
The next line though not totally wrong does assume that the iterators used are random access (which is true for vector).
for (OdpVec::iterator iter = vec.begin(); iter < vec.end(); iter++)
But this makes the code more brittle as a simple change in the typedef OdpVec will break the code without any warning. So to make this more consistent with normal iterator usage, use != when checking against end() and also prefer the pre increment operator:
for (OdpVec::iterator iter = vec.begin(); iter != vec.end(); ++iter)
shared_ptr::reset destroys the contents already in the shared_ptr. If you want to affect only that single shared_ptr reference, simply assign to it.
EDIT: In response to comment, you can fix it by changing the body of your for loop to:
if ((*iter)->id == id)
{
shpoutOdp = *iter;
return true;
}
EDIT2: That all said, why aren't you using std::find_if here?
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm> //for std::find_if
#include <functional> //for std::bind
struct Odp
{
int id;
int GetId()
{
return id;
}
Odp(int id)
{
this->id = id;
}
~Odp()
{
std::cout << "Destructing Odp " << id << std::endl;
}
};
typedef std::vector<shared_ptr<Odp> > OdpVec;
int main()
{
OdpVec vec;
vec.push_back(std::shared_ptr<Odp>(new Odp(0)));
vec.push_back(std::shared_ptr<Odp>(new Odp(1)));
vec.push_back(std::shared_ptr<Odp>(new Odp(2)));
OdpVec::iterator foundOdp = std::find_if(vec.begin(), vec.end(),
std::bind(std::equal_to<int>(), 0, std::bind(&Odp::GetId,_1)));
bool found = foundOdp != vec.end();
}
The nice thing about shared_ptr is that it handles the ref-counting internally. You don't need to manually increment or decrement it ever. (And that is why shared_ptr doesn't allow you to do so either)
When you call reset, it simply sets the current shared_ptr to point to another object (or null). That means that there is now one less reference to the object it pointed to before the reset, so in that sense, the ref counter has been decremented. But it is not a function you should call to decrement the ref counter.
You don't ever need to do that. Just let the shared_ptr go out of scope, and it takes care of decrementing the reference count.
It's an example of RAII in action.
The resource you need to manage (in this case the object pointed to by the shared_ptr) is bound to a stack-allocated object (the shared_ptr itself), so that its lifetime is managed automatically. The shared_ptr's destructor ensures that the pointed-to object is released when appropriate.
Hey, In C++, I have a vector of type:
vector<BaseClass*> myVector;
In which, I insert (push_back) pointers of derived classes into it.
Now, I want to pop back its elements so I do this:
vector<ADlgcDev*>::iterator iter;
for (iter = myVector.rbegin(); iter != myVector.rend(); iter++)
{
// but before I pop it, I need to shutdown it down
// so I cast this
// but this way, I'm unable to call the function
(DerivedClass*(*iter))->Shutdown();
myVector.pop_back();
}
but as mention in the comments before I pop it, I need to call its Shutdown() method and the cast is not working properly too. Any resolutions? or is impossible?
while (!myVector.empty())
{
((DerivedClass*)(myVector.back()))->Shutdown();
myVector.pop_back();
}
Notes:
You should probably use dynamic_cast instead of the hard cast. (If it's sure that there are only DerivedClass objects in the vector, why isn't it std::vector<DerivedClass>?)
You should probably not have to cast at all, since Shutdown() should be declared in the base class.
You should probably delete the objects, too, before you pop them off the vector. (But that might not be so.)
You should probably use a smart pointer which calls Shutdown() (and delete, probably).
Edit: Using std::vector<T>::clear(), as shown by markh44 is probably better than the pop_back().
Could you make Shutdown a virtual function in BaseClass? Then you wouldn't need a cast.
Also you'll probably have trouble removing items from a vector while iterating. I'd do it like this:
vector<BaseClass*>::iterator iter;
for (iter = myVector.rbegin(); iter != myVector.rend(); iter++)
{
(*iter)->Shutdown();
}
myVector.clear();
Edit: and another thing, ++iter is generally preferred over iter++.
The constructor casting doesn't work for pointers. Use static_cast if you're sure or dynamic_cast and check.
If Shutdown() is a virtual method of the Base class i.e. BaseClass::ShutDown() you should directly call iter->ShutDown();
Otherwise if the method isn't virtual you should use dynamic_cast.
vector<ADlgcDev*>::iterator iter;
for (iter = myVector.rbegin(); iter != myVector.end(); iter++)
{
DerivedClassA* a = dynamic_cast<DerivedClassA*>( *iter ) ;
if ( a ) a->ShutDownA();
else
{
DerivedClassB* b = dynamic_cast<DerivedClassB*>(*iter);
if ( b ) b->ShutDownB();
// ... repeat for every class in hierarchy that might be in the vector.
}
myVector.pop_back();
}
Anyway you're probably leaking memory, unless ShutDown() deletes the object from itself (which is generally a bad idea ) or you're keeping duplicated pointers and deleting them elsewhere, which is another risky idea.
Just wondering, because of a problem I am running into, is it possible to create a vector of pointers? And if so, how? Specifically concerning using iterators and .begin() with it, ie: How would I turn this vector into a vector of pointers:
class c
{
void virtual func();
};
class sc:public c
{
void func(){cout<<"using func";}
};
sc cobj;
vector<c>cvect
cvect.push_back(cobj);
vector<c>::iterator citer
for(citer=cvect.begin();citer<cvect.end();citer++)
{
citer->func();
}
Sure.
vector<c*> cvect;
cvect.push_back(new sc);
vector<c*>::iterator citer;
for(citer=cvect.begin(); citer != cvect.end(); citer++) {
(*citer)->func();
}
Things to keep in mind:
You'll need to cleanup after your self if you use dynamically allocated memory as I did in my example
e.g.:
for(...) { delete *i; }
This can be simplified by using a vector of shared_ptrs (like boost::shared_ptr). Do not attempt to use std::auto_ptr for this, it will not work (won't even compile).
Another thing to keep in mind, you should avoid using < to compare iterators in your loop when possible, it will only work for iterators that model a random access iterator, which means you can't change out your code to use e.g. a std::list.
vector <c> cvect is not a vector of pointers. It is a vector of objects of type c. You want vector <c*> cvect. and the you probably want:
cvect.push_back( new c );
And then, given an iterator, you want something like:
(*it)->func();
Of course, it's quite probable you didn't want a vector of pointers in the first place...
Yes it is possible, and in fact it is necessary to use pointers if you intend your vector to contain objects from an entire class hierarchy rather than of a single type. (Failing to use pointers will result in the dreaded problem of object slicing -- all objects are silently converted to base class type. This is not diagnosed by the compiler, and is almost certainly not what you want.)
class c
{
void virtual func();
};
class sc:public c
{
void func(){cout<<"using func";}
};
sc cobj;
vector<c*> cvect; // Note the type is "c*"
cvect.push_back(&cobj); // Note the "&"
vector<c*>::iterator citer;
for(citer=cvect.begin();citer != cvect.end();citer++) // Use "!=" not "<"
{
(*citer)->func();
}
Note that with a vector of pointers, you need to do your own memory management, so be very careful -- if you will be using local objects (as above), they must not fall out of scope before the container does. If you use pointers to objects created with new, you'll need to delete them manually before the container is destroyed. You should absolutely consider using smart pointers in this case, such as the smart_ptr provided by Boost.
Yes, sure.
// TestCPP.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
class c
{
public:
void virtual func() = 0;
};
class sc:public c
{
public:
void func(){cout<<"using func";}
};
int _tmain(int argc, _TCHAR* argv[])
{
sc cobj;
vector<c*> cvect;
cvect.push_back(&cobj);
vector<c*>::iterator citer;
for(citer=cvect.begin();citer<cvect.end();citer++)
{
(*citer)->func();
}
return 0;
}
Please note the declaration of vector<c*> cvect and the use of cvect.push_back(&cobj).
From the code provided, you are using iterator in a wrong way. To access the member an iterator is pointing to you must use *citer instead of citer alone.
You have create vector<c*> for a vector of pointers. Then use new to allocate the memory for c objects and push them into vector. Also, don't forget that you have to delete yourself and vector.clear() will not release the memory allocated for c objects. You have to store c as a vector of pointers here, otherwise the call to the virtual function will not work.
Try Boost Pointer Container Library. It has several advantages over regular vector of pointers, like:
my_container.push_back( 0 ); // throws bad_ptr
ptr_vector<X> pvec;
std::vector<X*> vec;
( *vec.begin() )->foo(); // call X::foo(), a bit clumsy
pvec.begin()->foo(); // no indirection needed