函数调用中的一元指针增量与函数调用之前/之后的增量
我试图理解一段代码,这是导致混乱的片段:
typedef map<int, Person, less<int> > people_map;
people_map people;
.
.
.
cout << "Erasing people of age 100" << endl;
for (people_map::iterator j = people.begin(); j != people.end();) {
if (j->second.GetAge() == 100)
{
people.erase(j++); // iterator is advanced before the erase occurs
}
else
++j; // advance the iterator
} // end of erase loop
混乱是:如果我想在函数调用后增加 j ,它会导致分段错误。我无法理解为什么:
我将其更改为这样的内容:
if (j->second.GetAge() == 100)
{
temp = j++;
j--;
people.erase(j); // iterator is advanced before the erase occurs
j=temp;
}
导致分段错误。
或像这样:
if (j->second.GetAge() == 100)
{
people.erase(j); // iterator is advanced before the erase occurs
j++;
}
导致分段错误。
这是完整的程序清单:
// disable warnings about long names
#ifdef WIN32
#pragma warning( disable : 4786)
#endif
#include <string>
#include <map>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iterator>
#include <functional>
using namespace std;
class Person {
// private members
string m_sName;
string m_sEmail;
int m_iAge;
public:
// constructor
Person(const string sName,
const string sEmail,
const int iAge) :
m_sName(sName), m_sEmail(sEmail), m_iAge(iAge) {
};
// default constructor
Person() : m_iAge(0) {
};
// copy constructor
Person(const Person & p) :
m_sName(p.m_sName), m_sEmail(p.m_sEmail), m_iAge(p.m_iAge) {
};
// operator =
Person & operator=(const Person & rhs) {
// don't assign to self
if (this == &rhs)
return *this;
m_sName = rhs.m_sName;
m_sEmail = rhs.m_sEmail;
m_iAge = rhs.m_iAge;
return *this;
};
// access private members
string GetName() const {
return m_sName;
};
string GetEmail() const {
return m_sEmail;
};
int GetAge() const {
return m_iAge;
};
}; // end of class Person
// function object to print one person
class fPrint {
ostream & m_os;
public:
// constructor - remember which stream to use
fPrint(ostream & os) : m_os(os) {
};
// person object arrives as a pair of key,object
void operator() (const pair <const int, const Person> & item) const {
m_os << "# " << item.first << " - name: "
<< item.second.GetName()
<< " - " << item.second.GetEmail()
<< ", age " << item.second.GetAge()
<< endl;
};
}; // end of class fPrint
// declare type for storing people (numeric key, person object)
typedef map<int, Person, less<int> > people_map;
int main(void) {
// make a map of people
people_map people;
// add items to list
people [1234] = Person("Nick", "[email protected]", 15);
people [4422] = Person("Fred", "[email protected]", 100);
people [88] = Person("John", "[email protected]", 35);
// insert a different way ...
people.insert(make_pair(42, Person("Abigail", "[email protected]", 22)));
// best to declare this on its own line :)
fPrint fo(cout); // instance of function output object
// print everyone (calls a function object to print)
cout << "Printing all using fPrint ..." << endl;
for_each(people.begin(), people.end(), fo);
// find someone by key
cout << "Finding person 4422 ..." << endl;
people_map::const_iterator i = people.find(4422);
if (i == people.end())
cout << "Not found." << endl;
else {
fo(*i); // dereference and print
// another way of printing -
// key itself is the "first" part of the map pair ...
cout << "Found key = " << i->first << endl;
// person object is the "second" part of the map pair...
cout << "Found name = " << i->second.GetName() << endl;
}
// Note, this will not work:
// fPrint (cout) (*i);
// However this will:
// 0, fPrint (cout) (*i);
// However I think the extra zero is a bit obscure. :)
// An alternative way of finding someone.
// Note - this will add them if they are not there.
// Since this is a reference changing it will change the person in the
// map. Leave off the & to get a copy of the person.
Person & p = people [1234];
cout << "Person 1234 has name " << p.GetName() << endl;
// Example of erasing an element correctly ...
// If we did the j++ as part of the for loop we would end up
// adding 1 to an iterator that pointed to an element that was
// removed which would lead to a crash. See Josuttis p 205.
cout << "Erasing people of age 100" << endl;
for (people_map::iterator j = people.begin(); j != people.end();) {
if (j->second.GetAge() == 100)
{
people.erase(j++); // iterator is advanced before the erase occurs
}
else
++j; // advance the iterator
} // end of erase loop
// now display who is left
cout << "Printing people left after erase ..." << endl;
for_each(people.begin(), people.end(), fo);
return 0;
} // end of main
I am trying to understand a code, here is fragment which is causing confusion:
typedef map<int, Person, less<int> > people_map;
people_map people;
.
.
.
cout << "Erasing people of age 100" << endl;
for (people_map::iterator j = people.begin(); j != people.end();) {
if (j->second.GetAge() == 100)
{
people.erase(j++); // iterator is advanced before the erase occurs
}
else
++j; // advance the iterator
} // end of erase loop
the confusion is: if i want to increment j after the function call it causes segmentation fault. I am not able to understand why:
I change it to something like this:
if (j->second.GetAge() == 100)
{
temp = j++;
j--;
people.erase(j); // iterator is advanced before the erase occurs
j=temp;
}
causes segmentation fault.
or like this:
if (j->second.GetAge() == 100)
{
people.erase(j); // iterator is advanced before the erase occurs
j++;
}
causes segmentation fault.
here is the complete program listing:
// disable warnings about long names
#ifdef WIN32
#pragma warning( disable : 4786)
#endif
#include <string>
#include <map>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iterator>
#include <functional>
using namespace std;
class Person {
// private members
string m_sName;
string m_sEmail;
int m_iAge;
public:
// constructor
Person(const string sName,
const string sEmail,
const int iAge) :
m_sName(sName), m_sEmail(sEmail), m_iAge(iAge) {
};
// default constructor
Person() : m_iAge(0) {
};
// copy constructor
Person(const Person & p) :
m_sName(p.m_sName), m_sEmail(p.m_sEmail), m_iAge(p.m_iAge) {
};
// operator =
Person & operator=(const Person & rhs) {
// don't assign to self
if (this == &rhs)
return *this;
m_sName = rhs.m_sName;
m_sEmail = rhs.m_sEmail;
m_iAge = rhs.m_iAge;
return *this;
};
// access private members
string GetName() const {
return m_sName;
};
string GetEmail() const {
return m_sEmail;
};
int GetAge() const {
return m_iAge;
};
}; // end of class Person
// function object to print one person
class fPrint {
ostream & m_os;
public:
// constructor - remember which stream to use
fPrint(ostream & os) : m_os(os) {
};
// person object arrives as a pair of key,object
void operator() (const pair <const int, const Person> & item) const {
m_os << "# " << item.first << " - name: "
<< item.second.GetName()
<< " - " << item.second.GetEmail()
<< ", age " << item.second.GetAge()
<< endl;
};
}; // end of class fPrint
// declare type for storing people (numeric key, person object)
typedef map<int, Person, less<int> > people_map;
int main(void) {
// make a map of people
people_map people;
// add items to list
people [1234] = Person("Nick", "[email protected]", 15);
people [4422] = Person("Fred", "[email protected]", 100);
people [88] = Person("John", "[email protected]", 35);
// insert a different way ...
people.insert(make_pair(42, Person("Abigail", "[email protected]", 22)));
// best to declare this on its own line :)
fPrint fo(cout); // instance of function output object
// print everyone (calls a function object to print)
cout << "Printing all using fPrint ..." << endl;
for_each(people.begin(), people.end(), fo);
// find someone by key
cout << "Finding person 4422 ..." << endl;
people_map::const_iterator i = people.find(4422);
if (i == people.end())
cout << "Not found." << endl;
else {
fo(*i); // dereference and print
// another way of printing -
// key itself is the "first" part of the map pair ...
cout << "Found key = " << i->first << endl;
// person object is the "second" part of the map pair...
cout << "Found name = " << i->second.GetName() << endl;
}
// Note, this will not work:
// fPrint (cout) (*i);
// However this will:
// 0, fPrint (cout) (*i);
// However I think the extra zero is a bit obscure. :)
// An alternative way of finding someone.
// Note - this will add them if they are not there.
// Since this is a reference changing it will change the person in the
// map. Leave off the & to get a copy of the person.
Person & p = people [1234];
cout << "Person 1234 has name " << p.GetName() << endl;
// Example of erasing an element correctly ...
// If we did the j++ as part of the for loop we would end up
// adding 1 to an iterator that pointed to an element that was
// removed which would lead to a crash. See Josuttis p 205.
cout << "Erasing people of age 100" << endl;
for (people_map::iterator j = people.begin(); j != people.end();) {
if (j->second.GetAge() == 100)
{
people.erase(j++); // iterator is advanced before the erase occurs
}
else
++j; // advance the iterator
} // end of erase loop
// now display who is left
cout << "Printing people left after erase ..." << endl;
for_each(people.begin(), people.end(), fo);
return 0;
} // end of main
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
擦除使被擦除元素的迭代器无效。
这不起作用,因为您将 temp 设置为等于 j 的旧值,因此您将继续使用无效的迭代器。后置自增的结果就是操作数的原始值。
我想你也可以这样做,它在功能上与工作代码相同,只是它不使用后增量的临时结果:
erase invalidates the iterator to the erased element.
This doesn't work because you set temp equal to the old value of j, and hence you'll keep using the invalidated iterator. The result of post-increment is the original value of the operand.
I suppose you could also do it like this, which is functionally the same as the working code, except it doesn't use the temporary result of post-increment:
擦除会使迭代器无效,这就是使用后缀增量的原因。它不传递高级迭代器来擦除,它传递当前迭代器,但作为副作用前进。
您的后缀增量有问题,这就是您的尝试失败的原因。
Erase invalidates your iterator, this is why postfix increment is used. It doesn't pass advanced iterator to erase, it passes current iterator but advances as a sideffect.
You have a problem with postfix increment, this is why your attempts have failed.