STL - erasing from a set

A

A B

Hello,

I am trying to do a "set difference" operation, to trying to take some
elements (objects) out of a set. I wrote a small sample program to
test it.

--------------------------------------
#include <iostream>
#include <cstdlib>
#include <set>
#include <vector>
#include <algorithm>

using namespace std;

class A {
public:
A();
~A();
};

A::A() {
cout << "Constructing A\n";
}
A::~A() {
cout << "Destructing A\n";
}


int main() {

A a;
A a2;
A a3;
A* ptr_a = &a;
A* ptr_a2 = &a2;
A* ptr_a3 = &a3;

set<A*> set_a;
set_a.insert(ptr_a); set_a.insert(ptr_a2); set_a.insert(ptr_a3);

set<A*> set2_a;
set2_a.insert(ptr_a); set2_a.insert(ptr_a2);

cout << "Before erase\n";

set_a.erase(set2_a.begin(), set2_a.end());

cout << "End of main\n";
return 0;
}

--------------------------------------

The idea is that set_a should contain only ptr_a3 after the "erase"
operation. Instead, what I get is:

Constructing A
Constructing A
Constructing A
Before erase
Segmentation fault

What am I missing? According to the STL documentation for "set",
applying "erase" to an iterator-delimited range should be a valid
operation.

Regards,
Andrey
 
A

Andy Champ

set_a.erase(set2_a.begin(), set2_a.end());
What am I missing? According to the STL documentation for "set",
applying "erase" to an iterator-delimited range should be a valid
operation.

It is. But the iterators you fed to set_a are iterators into set2_a.

The fact that they point to values which are also in set_a is not
relevant - they are not valid to give to set_a.

I'm surprised you didn't get a better diagnostic from your system. I
assume you have compiled in debug mode?

Andy
 
P

Paul Floyd

Hello,

I am trying to do a "set difference" operation, to trying to take some
elements (objects) out of a set. I wrote a small sample program to
test it.

set_a.erase(set2_a.begin(), set2_a.end());

Here you are attempting to erase from set_a using a pair of iterators
from set2_a. Since the pair of iterators are not in set_a, it fails.

I imagine that set_difference or set_symmetric_difference will do what
you want.

A+
Paul
--
Paul Floyd http://paulf.free.fr


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
D

Daniel Krügler

You said,


I understand that, but the problem is that this temporary container
cannot be a new (empty) set... it needs to be something that is filled
to the necessary capacity already. I wrote another sample program to
see if I could I could get set_symmetric_difference to work:

#include<iostream>
#include<cstdlib>
#include<set>
#include<vector>
#include<algorithm>

using namespace std;

int main() {

set<int> set_int;
set_int.insert(2);
set_int.insert(1);
set_int.insert(3);

set<int> set2_int;
set2_int.insert(2);

set<int> set_diff;

set_symmetric_difference(set_int.begin(), set_int.end(),
set2_int.begin(), set2_int.end(), set_diff.begin());

return 0;
}


of course, this fails with

[compiler curses omitted]

This is understandable, because

a) the iterator of set are const iterators.
b) there is no memory yet to insert (This means the compile time error
prevents a nasty runtime error here)

Just use an insert iterator adaptor like so for your last line:

std::set_symmetric_difference(set_int.begin(), set_int.end(),
set2_int.begin(), set2_int.end(),
std::inserter(set_diff, set_diff.begin()));
Of course, I could use std::set::erase to erase each value
individually, as you mention. But that means I would have to create a
loop. I thought there should be a way to do this in STL in a single
line.

With a C++0x-capable compiler you can write a single line:

std::for_each(set2_int.begin(), set2_int.end(),
[&](const std::set<int>::value_type& r) { set_int.erase(r); });

HTH & Greetings from Bremen,

Daniel Krügler
 
J

James Kanze

You said,
I understand that, but the problem is that this temporary container
cannot be a new (empty) set... it needs to be something that is filled
to the necessary capacity already.

Just the opposite, really. If the target container is a set, it
should be empty. IIRC, someone has already posted the correct
solution: use an insertion iterator for the output, e.g.:
I wrote another sample program to
see if I could I could get set_symmetric_difference to work:
#include <iostream>
#include <cstdlib>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;
int main() {

set<int> set_int;
set_int.insert(2);
set_int.insert(1);
set_int.insert(3);
set<int> set2_int;
set2_int.insert(2);
set<int> set_diff;
set_symmetric_difference(set_int.begin(), set_int.end(),
set2_int.begin(), set2_int.end(), set_diff.begin());

set_symmetric_difference(set_int.begin(), set_int.end(),
set2_int.begin(), set2_int.end(),
std::inserter(set_diff,
set_diff.begin()));
 
L

LR

[snippage + edited]
Andrey said:
#include <set>
#include <algorithm>
std::set<int> set_int; .....put suff in set_int
std::set<int> set2_int; .....put stuff in set2_int
std::set<int> set_diff;
.....set_diff should be empty here.

this won't compile.
std::set_symmetric_difference(set_int.begin(), set_int.end(),
set2_int.begin(), set2_int.end(), set_diff.begin());

try:

std::set_symmetric_difference(
set_int.begin(),
set_int.end(),
set2_int.begin(),
set2_int.end(),
std::insert_iterator< std::set<int> >(
set_diff,
set_diff.begin()
)
);



HTH

LR
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top