I'm currently learning C++ and ran into a little problem. The code below prints the address on the vector, but how do I let it spill the contents behind the address?
std::vector<BasePayroll*> emps;
emps.push_back(&Jane);
for (std::vector<BasePayroll*>::iterator it = emps.begin(); it != emps.end(); it++ ) {
std::cout << *it;
}
std::vector<BasePayroll*> emps; // when you dereference the iterator once you get
// what you have stored in the vector, a BasePayroll*
emps.push_back(&Jane);
for (std::vector<BasePayroll*>::iterator it = emps.begin(); it != emps.end(); it++ ) {
std::cout << *(*it); // do double dereferencing to get a BasePayroll& instead
}
You could also let a range-based for loop do the first level of dereferencing:
for(BasePayroll* pbpr : emps) {
std::cout << *pbpr;
}
For the obove to work you also need
std::ostream& operator<<(std::ostream& os, const BasePayroll& bpr) {
// output BasePayroll-data using bpr
return os;
}
Related
Say I have
vector<shared_ptr<string>> enemy;
how do I remove elements from the enemy vector?
Thanks for your help in advance
**Edit (code in context)
void RemoveEnemy( vector<shared_ptr<Enemy>> & chart, string id )
{
int i = 0;
bool found = FALSE;
for(auto it = chart.begin(); it != chart.end(); i++)
{
if(id == chart[i]->GetEnemyID() )
{
found = TRUE;
chart.erase(it);
}
}
the code above segfaults me
You remove elements the same way you remove any elements from any std::vector - via the std::vector::erase() method, for instance. All you need for that is an iterator to the desired element to remove.
In your case, since you are storing std::shared_ptr<std::string> objects rather than storing actual std::string objects, you may need to use something like std::find_if() to find the vector element containing the desired string value, eg:
void removeEnemy(string name)
{
auto iter = std::find_if(enemy.begin(), enemy.end(),
[&](auto &s){ return (*s == name); }
);
if (iter != enemy.end())
enemy.erase(iter);
}
UPDATE: in the new code you have added, you are incorrectly mixing indexes and iterators together. You are creating an infinite loop if the vector is not empty, as you never increment the it iterator that controls your loop, you are incrementing your index i variable instead (see what happens when you don't give your variables unique and meaningful names?). So you end up going out of bounds of the vector into surrounding memory. That is why you get the segfault error.
Even though you are (trying to) use an iterator to loop through the vector, you are using indexes to access the elements, instead of dereferencing the iterator to access the elements. You don't need to use indexes at all in this situation, the iterator alone will suffice.
Try this instead:
void RemoveEnemy( vector<shared_ptr<Enemy>> & chart, string id )
{
for(auto it = chart.begin(); it != chart.end(); ++it)
{
if (id == it->GetEnemyID() )
{
chart.erase(it);
return;
}
}
Or, using the kind of code I suggested earlier:
void RemoveEnemy( vector<shared_ptr<Enemy>> & chart, string id )
{
auto iter = std::find_if(chart.begin(), chart.end(),
[&](auto &enemy){ return (enemy->GetEnemyID() == id); }
);
if (iter != chart.end())
chart.erase(iter);
}
The problem with your code is that erase() invalidates the iterator. You must use it = chart.erase(it).
I like mine which will remove aliens at high speed and without any care for the ordering of the other items. Removal with prejudice!
Note: remove_if is most often used with erase and it will preserve the order of the remaining elements. However, partition does not care about the ordering of elements and is much faster.
partition-test.cpp:
make partition-test && echo 1 alien 9 alien 2 8 alien 4 7 alien 5 3 | ./partition-test
#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
#include <string>
#include <vector>
using namespace std;
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &container) {
bool comma = false;
for (const auto &x : container) {
if (comma)
os << ", ";
os << *x;
comma = true;
}
return os;
}
int main() {
vector<shared_ptr<string>> iv;
auto x = make_shared<string>();
while (cin >> *x) {
iv.push_back(x);
x = make_shared<string>();
}
cout << iv << '\n';
iv.erase(partition(begin(iv), end(iv),
[](const auto &x) { return *x != "alien"s; }),
end(iv));
cout << iv << '\n';
return 0;
}
Given a std:: list
std::list< int > myList
and a reference (or a pointer) to an element in that list
int& myElement | int* pElement
So, basically I know the address of that element
How can I get an std::list<int>::iterator to that element efficiently?
A slow yet working example is
const_iterator it
for( it = myList.begin(); it != &myElement; ++it)
{
// do nothing, for loop terminates if "it" points to "myElem"
}
Is there a quicker way? like
const_iterator it = magicToIteratorConverter( myList, myElem )
Case of vector (but I need list):
For a vector, you could do the following:
const int* pStart = &myVector[0] // address of first element
const int* pElement = &myElem; // address of my element
const idx = static_cast< int >( pElement- pStart ); // no need to divide by size of an elem
std::vector< int >::iterator it = myVector.begin() + idx;
Case of std::list:
a std::list<int>::iterator is not an int*, you need to access the element in the iterator and get its address. Also, std::find_if takes care of most of the boilerplate for you.
auto iter = std:find_if(myList.begin(), myList.end(),
[&myElement](const int & listElement)
{ return &myElement == &listElement; });
Writing the loop out yourself would look like:
auto iter = myList.end();
for(auto i = myList.begin(); i != myList.end(); ++i)
if(&*i == &myElement)
{
iter = i;
break;
}
This is actually a good question and IMHO a shame that there is no std way to do what OP has asked. If you understand that a list node looks essentially like this
struct list_node {
list_node* prev;
list_node* next;
T yourType;
}
it is bad that there is no default way to get to the node (the iterator is a pointer to the node) if you have a pointer to yourType without searching through the whole container.
Since std is not helping you have to get your hands dirty:
#include <list>
#include <iostream>
//This is essentially what you are looking for:
std::list<int>::iterator pointerToIter (int* myPointer) {
//Calculates the distance in bytes from an iterator itself
//to the actual type that is stored at the position the
//iterator is pointing to.
size_t iterOffset = (size_t)&(*((std::list<void*>::iterator)nullptr));
//Subtract the offset from the passed pointer and make an
//iterator out of it
std::list<int>::iterator iter;
*(intptr_t*)&iter = (intptr_t)myPointer - iterOffset;
//You are done
return iter;
}
int main () {
std::list<int> intList;
intList.push_back (10);
int* i1 = &intList.back ();
intList.push_back (20);
intList.push_back (30);
int* i3 = &intList.back ();
intList.push_back (40);
intList.push_back (50);
int* i5 = &intList.back ();
std::cout << "Size: " << intList.size () << " | Content: ";
for (const int& value : intList)
std::cout << value << " ";
std::cout << std::endl;
intList.erase (pointerToIter (i1));
intList.erase (pointerToIter (i3));
intList.erase (pointerToIter (i5));
std::cout << "Size: " << intList.size () << " | Content: ";
for (const int& value : intList)
std::cout << value << " ";
std::cout << std::endl;
return 0;
}
Output (to prove that it works as intended):
Size: 5 | Content: 10 20 30 40 50
Size: 2 | Content: 20 40
This works perfectly even if an implementation of std::list would use a different layout for the list-node or add some more members to it. I also included the assembler code generated to see that the function is essentially reduced to myPointer - 0x10 (0x10 = 16 is the size of 2 pointers on a 64bit machine).
Assembler (with at least -O1):
std::list<int>::iterator pointerToIter (int* myPointer) {
0: 48 8d 47 f0 lea rax,[rdi-0x10]
}
4: c3 ret
Given a list, you can only get to anything by starting from one end walking through it, making sure you don't go beyond the end.
const_iterator it, end;
for( it = myList.begin(), end = myList.end(); it!=end && it != &myElement; ++it)
{
// do nothing, for loop terminates if "it" points to "myElem"
// or if we don't find your element.
}
Of course, you could use a standard algorithm, like std::find to look for it.
Alternatively, you could keep hold of the iterator when you insert, and under many conditions it will still be valid later on.
If you want lookup speed, you should probably use something other than a list.
If you have something like
int x = 42;
int * this_might_be_handy = &x;
myList.insert(x);
myList now has a COPY of the number - it has the value 42, but in a different memory location.
If you kept pointers to ints in the list, that would be different. getting the value from the front of the list and looking at the address will not give the same address as x.
But you would have to manage them smartly.
This is a dissected, formalized (C++11) and commented version of the very interesting solution of Xatian above. That solution is O(1) (that is one of the reasons it is so interesting), but it assumes some things that should be taken into account (Xatian's deep knowledge of the STL implementation of lists is the other reason why it is so interesting).
#include <iostream>
#include <list>
#include <cstdint>
int main(void)
{
// ASSUMPTIONS:
// 1.- nullptr == 0
// 2.- A std::list iterator is an object that contains just one thing: a pointer to the body of the iterator.
// 3.- A std::list iterator has a constructor that admits a pointer to a body provided by the user, which creates the iterator with that (assumed) existing body.
using DataType = int;
using DataList = std::list<DataType>;
std::cout << "Nullptr= " << reinterpret_cast<size_t>(nullptr) << std::endl;
std::cout << "Size of a pointer = " << sizeof(nullptr) << ", size of iterator = " << sizeof(DataList::iterator) << std::endl;
static_assert(reinterpret_cast<size_t>(nullptr) == 0,
"In this compiler, nullptr is not 0 and this will not work");
// we have a list filled with something.
DataList mylist{1,2,3,4};
// and an iterator pointing to some data.
DataList::iterator itaux{mylist.begin()};
++itaux;
++itaux;
// 1. calculate the offset of the data in a list iterator w.r.t. the beginning of the iterator body
DataList::iterator it{nullptr}; // call the iterator constructor. Nullptr becomes the address of the body where the iterator would store prev/next/data
// since nullptr is assumed to be 0, this is the same as to declare an iterator with its body at 0x00000000
DataType & itp = *it; // this is a reference to the user's data in the iterator body
// that iterator is a fake and does not contain any data, but since we are only dealing with addresses, no problem...
DataType * aitp = & itp; // this gets the address equivalent to the reference, which is at some point in memory from 0
size_t iteroffset = reinterpret_cast<size_t>(aitp); // That address becomes, actually, the offset of the data w.r.t. the beginning of the iterator body
std::cout << "Offset from iterator body start to data = " << iteroffset << std::endl;
// 2. we can get the pointer to the data from our existing iterator
DataType * mypointer = &(*itaux);
// 3. we can create a valid iterator from the pointer to the data
DataList::iterator iter;
*(reinterpret_cast<intptr_t*>(&iter)) = reinterpret_cast<intptr_t>(mypointer) - iteroffset; // the address of the beginning of the body (mypointer-iteroffset) is stored into
// the pointer to the body that the iterator actually is
std::cout << "pointed element: " << (*iter) << std::endl;
return(0);
}
list<CPoint> l;
l.push_back( CPoint(1,2) );
l.push_back( CPoint(30,40) );
l.push_back( CPoint(4,6) );
l.push_back( CPoint(70,80) );
CPoint * point = 0;
for ( list<CPoint>::iterator iter = l.begin();
iter != l.end();
iter++)
{
cout << iter->x << " , " << iter->y << endl;
// compilation error, I can't typcast it like below?
point = (CPoint *) iter;
}
The problem with above is that how to typcast the iter in the loop to the actual data structure pointer? That way I can write code like point.x, point.yto say the least.
The above is the demo code I wrote but in reality I have this code in a search function. If an item is found in the list, it will return pointer to that item otherwise NULL. In order to get that pointer back I need to dereference the iterator back to the underlying data structure pointer but how? Thanks.
To fix your syntax error, you need to dereference iterator then take the address from the underneath object:
point = &*iter;
You'd better just use std::find/std::find_if and store the iterator which is returned from std::list.
auto it = std::find_if(l.begin(), l.end(),
[](const CPoint& cp) { return cp.x == 1 && cp.y == 2; } );
if (it != l.end()) // test iterator to see is desired CPoint is found
{
std::cout << (*it).x << " " << (*it).y << std::endl;
}
I am a little confused by the way begin and end work they seem to me to be inconsistant. When going forward and backwards they have different behaviors.
vector<Actor *> a;
a.push_back(new Actor(11));
a.push_back(new Actor(22));
a.push_back(new Actor(33));
vector<Actor *>::iterator it = a.begin();
int x =0;
while(a.begin()+x != a.end()){
cout << (*(a.begin()+x)) << "\n";
x++;
}
cout << "\n";
int y = 1; // if this is set to 0 then its a seg fault =/ when I access
while(a.end()-y != a.begin()){
cout << (*(a.end()-y)) << "\n";
y++;
}
Outputs
0x979a008
0x979a028
0x979a018
0
0x979a018
0x979a028
How can I get the expected pattern
0x979a008
0x979a028
0x979a018
0x979a018
0x979a028
0x979a008
Note that begin() points to the first element of the vector, but end() points past the last element. It's never safe to dereference end(), but you can compare iterators to it.
If the vector is empty, then begin() == end(), and you may not dereference either one.
A more idiomatic way to loop over a vector's elements is:
for (vector<Actor*>::iterator i = a.begin(); i != a.end(); ++i) {
// do something here
}
To iterate in reverse, it's simpler to use rbegin() and rend(), which work much the same way and begin()/end(), but iterate in reverse order:
for (vector<Actor*>::reverse_iterator i = a.rbegin(); i != a.rend(); ++i) {
// do something here
}
Also, if you don't intend to modify the elements, you should use a const_iterator (or const_reverse_iterator instead.
You should use reverse iterators:
int y = 0;
while(a.rbegin() +y != a.rend()){
cout << (*(a.rbegin()+y)) << "\n";
y++;
}
Or even better would be to use the overloaded ++ operator of the iterators themselves:
auto iter = a.rbegin();
while(iter != a.rend()){
cout << *(iter++) << "\n";
}
One very simple way to achieve that would be following
// first element to the last
auto it = a.begin()
while (it != a.end())
{
cout<<*it<<"\n";
++it;
}
cout<<"\n"
// Last element to first
auto rit = a.rbegin()
while(rit != a.rend())
{
cout<<*rit<<"\n";
++rit;
}
NB: Do not try to dereference a.end() and beyond. When y = 0 in your program the a.end() is dereferenced in the line cout << (*(a.end()-y)) << "\n"; This results in seg fault.
Elements of vector are contained in a sequence which can be accessed from begin() through end()-1. .end() points to one "past" the last element of the container and should not be dereferenced.
std::for_each(a.begin(), a.end(), [](const Actor *& a){ std::cout << a; });
std::for_each(a.rbegin(), a.rend(), [](const Actor *& a){ std::cout << a; });
auto print_actor = [](const Actor *& a){ std::cout << a; };
std::for_each(a.begin(), a.end(), print_actor);
std::for_each(a.rbegin(), a.rend(), print_actor);
I have a vector of pointers to objects. Each object stores a value and has a toString() function that returns that value as a string. I have an iterator to go through the vector and I need to extract the value of each object by calling toString(). The problem is, I can't figure out how to get the value.
This function is ultimately supposed to write the number to a file, but I'm using the cout for testing.
void writeNumbers(vector<Integer*>& input)
{
ofstream write;
write.open("Integers.txt");
vector<Integer*>::iterator iter = input.begin();
for (iter; iter < input.end(); iter++)
{
**std::cout << (*iter)->toString() << std::endl;**
}
write.close();
I get an Access Violation error which points me to the toString() function:
std::string Integer::toString()
{
std::stringstream ss;
ss << *(this)->value;
return ss.str();
}
toString() works fine whenever I don't try to access it through the iterator.
Edit: Value in toString is actually a pointer to a number.
Edit2: New writeNumbers:
void writeNumbers(vector<Integer*>& input)
{
ofstream write;
write.open("Integers.txt");
vector<Integer*>::iterator iter = input.begin();
for (iter; iter != input.end(); iter++)
{
std::cout << (*iter)->toString() << std::endl;
}
write.close();
}
Final Edit: Alright, the problem turned out to be a borked constructor that was failing to initialize a pointer properly, so I was WAY off base on where the problem actually was. :)
Integer::Integer(string input)
{
if(isNaN(input))
value = new int(atoi(input.c_str()));
}
So it should have been !isNaN, plus I fixed the problem of initializing it on bad input:
//New constructor, works 100%
Integer::Integer(string input)
{
if(!isNaN(input))
value = new int(atoi(input.c_str()));
else
value = new int(0);
}
Your toSting() has the issue. Change
ss <<*(this)->value;
to
ss << value;
EDIT: This is not an error, but a general advice when using iterators. Dont use < to check for end, use !=.
iter < input.end()
It should be like this:
iter != input.end()
This is because for certain containers, the < operator will not do what you expect. As a result, at some point you could be dereferencing input.end() itself, which points at nothing.