I want to solve a problem regarding numbers saved in a tree structure.
I would like to create one class called Tree and another one called Element (in this case would be an Integer but it could be whatever) and make it the most adequate way based on C++ standards. It should be possible to add childs to a specific element in the tree and traceback the parent of each element.
#include <iostream>
#include <vector>
class Element
{
public:
Element() = delete;
explicit Element(int value, Element* parent = nullptr):
value_(value), parent_(parent), children_() {}
int getValue() const { return value_; }
Element* getParent() { return parent_; }
// it will throw if idx out of bounds
Element* getChild(size_t idx) { return children_.at(idx).get(); }
size_t numChildren() const { return children_.size(); }
Element* insertChild(int value)
{
std::cout << "new elem: " << value << std::endl;
children_.emplace_back(std::make_unique<Element>(value, this));
return children_.back().get();
}
bool moveChildren2Parent()
{
if (isRoot()) return false;
for (auto& c : children_)
{
// children change parent
c->parent_ = parent_;
parent_->children_.emplace_back(std::move(c));
}
children_.clear();
return true;
}
bool removeChild(size_t idx)
{
if (children_.size() <= idx) return false;
children_.erase(children_.begin()+idx);
return true;
}
bool isRoot() { return parent_ == nullptr; }
private:
int value_;
Element* parent_;
std::vector<std::unique_ptr<Element> > children_;
};
void checkChilds(Element* element) {
for (int i = 0; i < element->numChildren(); i++)
{
if (element->getChild(i)->numChildren() == 1)
{
element->getChild(i)->moveChildren2Parent();
element->removeChild(i);
i--;
} else if (element->getChild(i)->numChildren() > 1)
{
checkChilds(element->getChild(i));
}
}
}
int main()
{
auto root = std::make_shared<Element>(0);
Element* _ = root->insertChild(1)->insertChild(3)->insertChild(5);
Element* last_child = root->insertChild(2)->insertChild(4)->insertChild(7);
last_child->getParent()->insertChild(6);
for (int i=0;i<root->numChildren();i++)
{
if (root->getChild(i)->numChildren()==1)
{
root->getChild(i)->moveChildren2Parent();
root->removeChild(i);
i--;
}
else if (root->getChild(i)->numChildren()>1)
{
checkChilds(root->getChild(i));
}
}
return 0;
}
My objective is to create a tree and after if each element just has one child remove that element while keeping the leaves.
My code works but I would like to know improvements to make it better looking based on C++ standards.
EDIT
Thanks to the answer #pptaszni and after adapting it to my specific problem at hand this is the result. I think my implementation to go over all the elements checking if the number of childs they have is equal 1 and if so remove is not nicely written. Do you know how could I optimize it (the last for loop in main and function checkChilds)?
is there any specific reason you need two different class for element and tree?
i suggest, have just one class which have one data member which will store a node value and two pointers to point at two different child objects.
following is the suggestion based on what i have have understood from your question.
class Node
{
int value;
Node* left_child = nullptr;
Node* right_child = nullptr;
//methods for modifying tree.
};
To answer your first question: don't use operator[], because it inserts default-constructed element if it doesn't exist in the map. You can use at instead.
Then about your architecture: it doesn't look very good, because having a child, it's not obvious how to get parent, having a parent, it's not obvious how to get it's children, your std::map key is supposed to be unique and you also use it as a value for your Elements. I suggest to apply at least the following:
class Element
{
public:
Element() = delete;
explicit Element(int value, Element* parent = nullptr):
value_(value), parent_(parent), left_child_(nullptr), right_child_(nullptr) {}
int getValue() const { return value_; }
Element* getParent() { return parent_; }
Element* getLeftChild() { return left_child_.get(); }
Element* getRightChild() { return right_child_.get(); }
Element* insertLeftChild(int value)
{
if (left_child_)
{
std::cout << "already exists" << std::endl;
return left_child_.get(); // already exists
}
std::cout << "new left elem: " << value << std::endl;
left_child_ = std::make_unique<Element>(value, this);
return left_child_.get();
}
bool isRoot() { return parent_ == nullptr; }
private:
int value_;
Element* parent_;
std::unique_ptr<Element> left_child_;
std::unique_ptr<Element> right_child_;
};
int main()
{
auto root = std::make_shared<Element>(1);
Element* last_child = root->insertLeftChild(2)->insertLeftChild(3)->insertLeftChild(4);
std::cout << last_child->getValue() << std::endl;
std::cout << last_child->getParent()->getValue() << std::endl;
std::cout << last_child->getParent()->getParent()->getValue() << std::endl;
std::cout << last_child->getParent()->getParent()->getParent()->getValue() << std::endl;
std::cout << last_child->getParent()->getParent()->getParent()->isRoot() << std::endl;
return 0;
}
Now you have the access to parent and children from every element and you can start building your tree. Then there are further concerns like Element comparison operator (if needed), only 2 children per node or maybe more, pointers invalidation on every tree modification etc. It is a big topic in general.
======= EDIT =========
To answer OP's concern about multiple children, and to provide an example of removing the node while preserving the leaves (children):
class Element
{
public:
Element() = delete;
explicit Element(int value, Element* parent = nullptr):
value_(value), parent_(parent), children_() {}
int getValue() const { return value_; }
Element* getParent() { return parent_; }
// it will throw if idx out of bounds
Element* getChild(size_t idx) { return children_.at(idx).get(); }
size_t numChildren() const { return children_.size(); }
Element* insertChild(int value)
{
std::cout << "new elem: " << value << std::endl;
children_.emplace_back(std::make_unique<Element>(value, this));
return children_.back().get();
}
bool moveChildren2Parent()
{
if (isRoot()) return false;
for (auto& c : children_)
{
// children change parent
c->parent_ = parent_;
parent_->children_.emplace_back(std::move(c));
}
children_.clear();
return true;
}
bool removeChild(size_t idx)
{
if (children_.size() <= idx) return false;
children_.erase(children_.begin()+idx);
return true;
}
bool isRoot() { return parent_ == nullptr; }
private:
int value_;
Element* parent_;
std::vector<std::unique_ptr<Element> > children_;
};
int main()
{
auto root = std::make_shared<Element>(1);
Element* last_child = root->insertChild(2)->insertChild(3)->insertChild(4);
last_child->getParent()->insertChild(5);
std::cout << "numChildren: " << last_child->getParent()->numChildren() << std::endl;
last_child->getParent()->moveChildren2Parent();
std::cout << "numChildren: " << last_child->getParent()->numChildren() << std::endl;
last_child->getParent()->removeChild(0); // element with value 3 removed, it's children already transferred
std::cout << last_child->getValue() << std::endl;
std::cout << last_child->getParent()->getValue() << std::endl;
std::cout << last_child->getParent()->getParent()->getValue() << std::endl;
std::cout << last_child->getParent()->getParent()->isRoot() << std::endl;
return 0;
}
It is just one of many possibilities, particular implementation choice always depends on the system requirements.
You have several problems with your code there. The most glaring one I can see is that you are freely converting between int pairs and elements. Classes provide a way to strongly type our code, if int, int is mean to represent an Element, make it an Element!
The reason you have to declare a default constructor is because you have already declared a constructor. The compiler will only generate a default one for you if you havnt already declared one.
To make the compiler explcitly generate one for you use default. Like this:
Element() = default;
To fix your weak typing issues you should use Element for m_parent and when adding an item to the Tree, if you need to do stuff like setting values of the parent then do that to the item you are passed to add. Like this
...
private:
Element m_parent;
...
void addElement(const Element& parent, int value)
{
Element elem = Element(value, parent);
m_elements.insert(std::pair<int,Element>(value,elem));
}
...
You also probably want to use a different container than std::map. If you want to have a concept of 'elements' then I would use std::set, store the element value or key as a member and overload the < operator (to allow sorting) to return the operation on the values/keys. std::set would allow you to search the tree (using a lambda with find_if) for keys or values as well as anything else (like parent matching).
This use of storing the parent as another Element also enables you to iterate back up the tree if you wanted too (independent of your container).
Related
I have a decision tree that includes node and answer that leads us to another nodes. Answers begin with ":" and nodes are the rest.
I have to do a function that delete a subtree from a specific node. For example If I want to delete node "brand?", I want that after that the tree will print from car-color? to blue-is-beautiful
I don't success doing this deletion in the right way because I think I have to delete also the answer red and don't know how to do that.
class Answer
{
public:
string ans;
Node* son;
Answer(string s, Node* p) { ans = s; son = p; }
};
class Node
{
public:
Node(string v) { isLeaf = true; value = v; }
list<Answer*> answersList;
string value;
bool isLeaf;
};
void Tree::del(Node* t)
{
if (t->isLeaf)
return;
for (list<Answer*>::iterator it = t->answersList.begin(); it != t->answersList.end(); it++)
{
del((*it)->son);
delete((*it));
*it = NULL;
}
if (t)
{
delete t;
t = NULL;
}
}
Now having understood the problems (highly restrictive requirements and what is causing your code to fail), I now have an answer for you.
The issue is, that you need to remove the node you've deleted from the collection it is stored in.
For this purpose, you need to use an alternate version of your search to detect, which child has the value you are looking for.
Due to the requirement of 'not adding any additional functions', there are two ways to go about this.
One is to employ recursion using an anonymous function, the other is 'check the child prior to diving into it'.
The following code fragment uses a DIY-Lambda-Functor, which employs the recursion method.
void Tree::deletefromNode(string val)
{
bool didFindValue = false;
std::function<bool (Node *, const string &)> functor;
class Functor
{
public:
Functor(Tree *owner, bool &didFindValue) : owner(owner), didFindValue(didFindValue)
{
}
bool deleteFromNode(Node *node, const string &value)
{
bool foundMatch = false;
if (node)
{
foundMatch = (node->value == value);
if (!foundMatch)
{
for (list<Answer*>::iterator it = node->answersList.begin(); it != node->answersList.end();)
{
Node *childNode = (*it)->son;
if (deleteFromNode(childNode, value))
{
owner->del(childNode);
it = node->answersList.erase(it);
didFindValue = true;
}
else
it++;
}
}
}
return foundMatch;
}
private:
Tree *owner;
bool &didFindValue;
};
Functor(this, didFindValue).deleteFromNode(root, val);
if (didFindValue)
cout << "Value not found" << endl;
}
I get a LNK 2019 error in VS.
I have read a couple of similiar problems,but could not understand what i should do.As much as i understood VS can't find the template class code for some reason.I am not sure.
#include "pch.h"
#include <iostream>
#include <assert.h>
template<typename T>
struct item {
item* pointer = nullptr;
T value;
};
template <typename T>
class stack {
private:
item<T>* top;
public:
stack() { top = nullptr; };
~stack();
void push(const T& s) {
item<T>* p = top;
top = new item<T>;
assert(top != nullptr);
top->value = s;
top->pointer = p;
std::cout << "The item has been pushed." << std::endl;
}
void pop() {
T s;
if (!top) {
std::cout << "The stack is empty." << std::endl;
}
else {
s = top->value;
item<T>* p = top;
top = top->pointer;
delete p;
std::cout << "The item has been popped." << std::endl;
}
};
void check() {
if (!top) { std::cout << "The stack is empty." << std::endl; }
else { std::cout << "It has elements in it." << std::endl; }
}
};
int main()
{
stack<int> test;
return 0;
}
I want afterwards to be able to push and pop elements.So that i can continue on with my project.
You have declared a destructor for stack here:
~stack();
but you don't define it. Change the above to
~stack() { /* Clean up resources here. */ }
and it should work.
In C++, if you declare a destructor, you have to define it. Even if the destructor is pure virtual, you still have to define it or else you'll get linker error, as is the case here. If you are fine with the default destructor, but still want to declare it for some reason, for instance, to make it virtual, you can use the keyword default:
virtual ~stack() = default;
You can learn more about the default keyword here.
I get some errors when I try to run the next code:
// tree.cpp
// compile with: g++ -std=c++11 tree.cpp -o tree
#include <iostream>
#include <future>
using namespace std;
int valtab[127]; // used for integer values of variables
class Tree; // forward declare
class Node {
protected:
Node() { use = 1; }
virtual void print(ostream &os) = 0;
virtual ~Node() { }
virtual int eval() = 0;
private:
friend class Tree;
friend ostream& operator<<(ostream&, const Tree&);
int use; // reference count
};
class Tree {
public:
Tree(int n); // constant
Tree(char id); // variable
Tree(char op, Tree t); // unary operator
Tree(char op, Tree left, Tree right); // binary operator
Tree(const Tree &t) { p = t.p; ++p->use; }
~Tree() { if (--p->use == 0) delete p; }
void operator=(const Tree &t);
int eval() { return p->eval(); }
private:
friend class Node;
friend ostream& operator<<(ostream &os, const Tree &t);
Node *p; // polymorphic hierarchy
};
void Tree::operator=(const Tree &t)
{
++t.p->use;
if (--p->use == 0)
delete p;
p = t.p;
}
ostream& operator<<(ostream &os, const Tree &t)
{
t.p->print(os);
return os;
}
class LeafNode: public Node {
private:
friend class Tree;
void print(ostream &os) = 0;
virtual int eval() = 0;
};
class IntNode: public LeafNode {
public:
int eval() { return n; }
private:
friend class Tree;
int n;
void print(ostream &os) { os << n ;}
IntNode(int k): n(k) { }
};
class IdNode: public LeafNode {
public:
int eval() { return valtab[name]; }
private:
friend class Tree;
char name;
void print(ostream& o) { o << name; }
IdNode(char id): name(id) { }
};
class UnaryNode: public Node {
public:
int eval();
private:
friend class Tree;
const char op;
Tree opnd;
UnaryNode(char a, Tree b): op(a), opnd(b) { }
void print(ostream& o) { o << "(" << op << opnd << ")"; }
};
int UnaryNode::eval()
{
switch (op) {
case '-': return (-opnd.eval());
case '+': return (+opnd.eval());
default: cerr << "no operand" << endl;
return 0;
}
}
class BinaryNode: public Node {
public:
int eval();
private:
friend class Tree;
const char op;
Tree left;
Tree right;
BinaryNode(char a, Tree b, Tree c): op(a), left(b), right(c) { }
void print(ostream &os) { os << "(" << left << op << right << ")"; }
};
int BinaryNode::eval()
{
switch (op) {
case '-': {
future<int> left = async(launch::async, left.eval());
future<int> right = async(launch::async, right.eval());
//return (left.get() - right.get());
}
case '+': return (left.eval() + right.eval());
case '*': return (left.eval() * right.eval());
default: cerr << "no operand" << endl;
return 0;
}
}
Tree::Tree(int n) { p = new IntNode(n); }
Tree::Tree(char id) { p = new IdNode(id); }
Tree::Tree(char op, Tree t) { p = new UnaryNode(op, t); }
Tree::Tree(char op, Tree left, Tree right) { p = new BinaryNode(op, left, right); }
int main()
{
valtab['A'] = 3; valtab['B'] = 4;
cout << "A = 3, B = 4" << endl;
Tree t1 = Tree('*', Tree('-', 5), Tree('+', 'A', 4));
Tree t2 = Tree('+', Tree('-', 'A', 1), Tree('+', t1, 'B'));
cout << "t1 = " << t1 << ", t2 = " << t2 << endl;
cout << "t1 = " << t1.eval() << ", t2 = " << t2.eval() << endl;
return 0;
}
This error I received:
error: 'class std::future<int>' has no member named 'eval'
I want to change the program so that expressions are evaluated in a parallel fashion. But I'm stuck with the future implementation, I do not quite understand how it works. Well, I understands how it works but I don't understand why I'm receiving these errors.
I hope some one can give me some tips or point me in the right direction.
You're trying to invoke a virtual member function as an async, but not properly providing the object to pin it against. Further, your use of same-id local vars, while not directly introducing an error, makes this incredibly hard to read.
I believe this is what you're shooting for:
auto eLeft = std::async(std::launch::async, std::bind(&Tree::eval, &this->left));
auto eRight = std::async(std::launch::async, std::bind(&Tree::eval, &this->right));
return (eLeft.get() - eRight.get());
Though, to be completely honest, this seems overkill. I see no sense in spinning up two asyncs just to then wait on both. Why not spin up one, then use the current thread to perform the other half of of your task:
auto eRight = std::async(std::launch::async, std::bind(&Tree::eval, &this->right));
return (left.eval() - eRight.get());
The parameter to std::async is a function (or more precisely, a Callable).
In particular, you do not invoke the function yourself (which would yield the return value). Invoking is done by std::async.
So these lines:
future<int> left = async(launch::async, left.eval());
future<int> right = async(launch::async, right.eval());
Should instead read something like:
future<int> left_result = std::async(launch::async, [this]() { return left.eval(); });
future<int> right_result = std::async(launch::async, [this]() { return right.eval(); });
Note that the function call is now wrapped in a lambda. Note also that you also reused the names for left and right in your original code, which is more trouble. I renamed them here to make it work.
As usual, since you now have concurrency in your program, you need to care about data races . Currently this seems to be fine, as all nodes in the tree are distinct, so the async calls don't share any data with each other. But keep it in mind for any future changes.
I was trying to build my own binary search tree. However , my tree is not getting built. Please see code below and help.
#include<iostream>
#include<string>
using namespace std;
class Binarytree
{
private:
struct node
{
int data;
node *left;
node *right;
};
node *root;
public:
Binarytree();
void insertdata(node*,int);
void deletedata();
void printdata(node*);
void userprint(char);
void getdata(int);
};
Binarytree::Binarytree()
{
root=NULL;
cout<<"Setting root as NULL"<<endl;
}
void Binarytree::insertdata(node* temp3,int temp)
{ cout << "in insert data"<<endl;
node Dummy=node();
Dummy.data=temp;
Dummy.left=NULL;
Dummy.right=NULL;
cout << "Data To be inserted is "<<temp <<endl;
if (temp3 == NULL)
{ cout<<"Found NULL ROOT"<<endl;
temp3=&Dummy;
cout << "Entered a Data in tree"<<endl;
cout<<"Data in root"<<root->data<<endl;
}
else if (temp3->data > temp)
{ cout<<"Making a Left Recursive Call"<<endl;
insertdata(temp3->left,temp);
}
else
{ cout<<"Making a right Recursive Call"<<endl;
insertdata(temp3->right,temp);
}
}
void Binarytree::getdata(int check)
{ cout <<"in getdata"<<endl;
cout << "before insertdata"<<endl;
insertdata(root,check);
}
void Binarytree::printdata(node* printrt)
{
if (printrt ==NULL)
cout << "Nothing to print";
else
{ cout << printrt->data << endl;
printdata(printrt->left);
printdata(printrt->right);
}
}
void Binarytree::userprint(char in)
{ node* data;
data=root;
if (in == 'Y' || in == 'y')
printdata(data);
}
void main()
{ Binarytree element=Binarytree();
int userdata,i=0;
bool check = true;
while(check)
{ cout <<"Please Enter your Data"<<endl;
cin >> userdata;
element.getdata(userdata);
cout<<"FUnction returned to main"<<endl;
i++;
if(i==5)
check=false;
}
element.userprint('Y');
}
The very first value is not getting inserted in root pointer. I know there are lots of code available for doing this but if i don't code it my own I feel my learning will be limited.
So please help in figuring error in this code.
Having really tried to compile and there might be other problems... but
change
void Binarytree::insertdata(node* temp3,int temp)
to
void Binarytree::insertdata(node* &temp3,int temp)
so that the node created inside insertdata really modifies the outside pointer.
and change
node Dummy=node();
Dummy.data=temp;
Dummy.left=NULL;
Dummy.right=NULL;
to
node *Dummy=new node();
Dummy->data=temp;
Dummy->left=NULL;
Dummy->right=NULL;
As I said there might be other problems... you should worry about deleting nodes and all that...
Alternative you could create nodes outside of insertdata() and keep the same signature.
Anyway, good luck
The root cause (if you'll pardon the pun) is the way you're adding things to the root of the tree. Your code creates a temporary variable called Dummy on the stack and then takes its address. That's the first mistake because that temporary variable gets destroyed when the function ends.
The second problem is that in order to change the value of a pointer that you pass to a function, you have to pass a pointer to a pointer. In other words, your member function that was insertdata(node *, int) must become insertdata(node **, int)if you want to actually change the passed pointer rather than just a local copy as your original code had done.
To illustrate that fact, try this code.
#include <iostream>
int Y = 99;
void makeitsix(int n) {
n = 6;
}
void pointToY(int *ptr) {
ptr = &Y;
}
int main()
{
int x = 5;
int *p = &x;
std::cout << "x = " << x << ", *p = " << *p << std::endl;
makeitsix(x);
pointToY(p);
std::cout << "x = " << x << ", *p = " << *p << std::endl;
return 0;
}
When makeitsix() gets called, it's only the local copy of n that is altered, and not the value of 5 that was originally passed in. Similarly, ptr in the pointToY() function is only altering a local copy of ptr and not p that was used to call the function from within main(). If it were not so, an invocation such as makeitsix(3) would lead to some very strange effects!
I took the liberty of changing things somewhat in your code to make it a little cleaner, including
giving the node structure its own constructor
creating an extractor for the Binarytree
removing the various diagnostic printout statements (for brevity)
making the tree printout look more like a tree with the root to the left and the branches extending rightward
made some member functions private
and a few other minor things. The complete working code is below:
#include<iostream>
#include<string>
class Binarytree
{
private:
struct node
{
node(int d=0) : data(d), left(NULL), right(NULL) {};
int data;
node *left;
node *right;
};
node *root;
void insertdata(node**,int);
std::ostream& printdata(std::ostream &out, node*, int depth=0);
public:
Binarytree() : root(NULL) {};
std::ostream &printTo(std::ostream &out);
void insert(int);
};
void Binarytree::insertdata(node** temp3,int temp)
{
node *Dummy=new node(temp);
if (*temp3 == NULL) {
*temp3=Dummy;
} else if ((*temp3)->data > temp) {
insertdata(&((*temp3)->left),temp);
} else {
insertdata(&((*temp3)->right),temp);
}
}
void Binarytree::insert(int check)
{
insertdata(&root,check);
}
std::ostream &Binarytree::printdata(std::ostream &out, node* printrt, int depth)
{
if (printrt != NULL)
{
printdata(out, printrt->left, depth+1);
for (int i = 0; i < depth; ++i)
out << '\t';
out << printrt->data << std::endl;
printdata(out, printrt->right, depth+1);
}
return out;
}
std::ostream &Binarytree::printTo(std::ostream &out)
{
return printdata(out, root);
}
std::ostream &operator<<(std::ostream &out, Binarytree &b)
{
return b.printTo(out);
}
int main()
{
Binarytree element;
int userdata,i=0;
bool check = true;
while(check)
{
std::cout << "Please Enter your Data" << std::endl;
std::cin >> userdata;
element.insert(userdata);
i++;
if(i==5)
check=false;
}
std::cout << "Tree:\n" << element << std::endl;
return 0;
}
In the following example I remove from list some elements in the range for which the application of pr2 to it return true.
m_list.remove_if(pr2(*tmp_list));
It seems to me it is necessary to delete this objects, which was removed above, becase when I create it I use "new" (new CRectangle()). How I can do this? I don't know which (and how much) elements will be remove after remove_if.
// test_cconnection.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <conio.h>
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
class CDrawObject
{
public:
virtual ~CDrawObject()
{
cout << "Drop CDrawObject: " << id_ << endl;
}
int getId() const
{
return id_;
}
virtual void draw()
{
}
protected:
static int id;
int id_;
};
class CRectangle : public CDrawObject
{
public:
CRectangle()
{
id_ = id++;
}
~CRectangle()
{
cout << "Drop CRectangle: " << id_ << endl;
}
virtual void draw()
{
cout << "CRectangle, id: " << id_ << endl;
}
};
class CMarker : public CDrawObject
{
CDrawObject* obj;
public:
CMarker(CDrawObject* obj_)
{
obj = obj_;
}
~CMarker()
{
cout << "Delete marker of object with id: " << obj->getId() << endl;
}
CDrawObject* getObject() const
{
return obj;
}
virtual void draw()
{
cout << "CMarker of oject with id: " << obj->getId() << endl;
}
};
int CDrawObject::id = 0;
// predicate for compare objects with int id
class pr : public std::unary_function<CDrawObject*, bool>
{
private:
int id_;
public:
pr(int id): id_(id) {}
bool operator()(CDrawObject* arg) const
{
return (arg->getId() == id_);
}
};
// predicate for check objects with type CMarker and
// compare with CDrawObject* obj
class pr2 : public std::unary_function<CDrawObject*, bool>
{
private:
CDrawObject* obj_;
public:
pr2(CDrawObject* obj)
{
obj_ = obj;
}
bool operator()(CDrawObject* arg) const
{
if (dynamic_cast<CMarker*>(arg))
return ((dynamic_cast<CMarker*>(arg))->getObject() == obj_);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
list<CDrawObject*> m_list;
list<CDrawObject*>::iterator i_list, tmp_list;
m_list.push_back(new CRectangle());
tmp_list = m_list.end();
m_list.push_back(new CMarker(*--tmp_list));
m_list.push_back(new CMarker(*tmp_list));
m_list.push_back(new CRectangle());
tmp_list = m_list.end();
m_list.push_back(new CMarker(*--tmp_list));
m_list.push_back(new CRectangle());
tmp_list = m_list.end();
m_list.push_back(new CMarker(*--tmp_list));
m_list.push_back(new CMarker(*tmp_list));
// print on screen items of m_list
for (i_list = m_list.begin(); i_list != m_list.end(); ++i_list)
(*i_list)->draw();
// get an iterator to the first element in the range with id_ = 2
tmp_list = find_if(m_list.begin(), m_list.end(), pr(2));
if (tmp_list != m_list.end())
{
// remove from list all elements with type CMarker
// and CDrawObject = tmp_list
m_list.remove_if(pr2(*tmp_list));
}
cout << endl << "--------" << endl;
// print on screen items of m_list
for (i_list = m_list.begin(); i_list != m_list.end(); ++i_list)
(*i_list)->draw();
_getch();
return 0;
}
Well you could:
HACKISH: delete the object in the predicate.
ANNOYING: Stay away from remove_if and implement everything it does on your own except add the delete.
BETTER: use RAII objects rather than raw pointers. Some sort of smart ptr in other words.
The way it's implemented at the moment, you won't be able to delete the memory that you allocated for those objects. In general, it takes some extra effort to perform memory cleanup when you have containers of pointers to dynamically allocated memory. Here's one way to do it:
// Assume there's a predicate function called ShouldRemove(int value);
list<int> my_list;
// initialization...
for (list<int>::iterator itr = my_list.begin(); itr != my_list.end(); ) {
if (ShouldRemove(**itr)) {
delete *itr;
itr = my_list.erase(itr);
} else {
++itr;
}
}
But as Noah Roberts pointed out, this is all much easier to deal with if you store your pointers as smart pointers that clean up after themselves.
Standalone remove_if never resizes a collection and returns an iterator pointing to the first object for which predicate is false.
It is therefore more appropriate for your task.