Boost Fibonacci Heap - c++

I was looking at the code of the boost Fibonacci heap, and in many places, I saw a variable called _id of type ID (part of the template) being used like this:get(_id, d), where d is of type T&, where T is part of the template. What is the purpose of this, and what would the equivalent of this be with only the default c++ standard libraries.
Here is the code for the fibonacci heap:
void push(const T& d) {
++_n;
size_type v = get(_id, d);
_key[v] = d;
_p[v] = nil();
_degree[v] = 0;
_mark[v] = false;
_child[v] = nil();
if (_root == nil()) {
_root = _left[v] = _right[v] = v;
//std::cout << "root added" << std::endl;
} else {
size_type u = _left[_root];
_left[v] = u;
_right[v] = _root;
_left[_root] = _right[u] = v;
if (_compare(d, _key[_root]))
_root = v;
//std::cout << "non-root node added" << std::endl;
}
}

Related

Implementation of Auction Algorthm via Boost Graph Library C++

As I cited in previous question:
Is it possible to generate multiple custom vertices using the Bundle Properties from Boost Graph Library?
Boost Maximum Weighted Matching in undirected bipartite random graphs hangs in an infinite loop
I'm working on an application benchmark that compare the performance of the boost maximum weighted matching and auction algorithm for the transportation problem on solving the assignment problem for bipartite graphs.
Currently I've implemented a version of the auction algorithm using the bundle proprieties of boost graph library, this implementation is inspired by a vector version from github. I've done this in order to put on the same level both algorithms, to make a fair benchmark. Here it is:
#include "../include/Auction.h"
#include "../include/BipartiteGraph.h"
void auction_algorithm(Graph& graph, const int& n, duration& elapsed) {
const Weight eps = 1;
int unassigned_bidders = n;
GraphProp& gp = graph[boost::graph_bundle];
EdgeFilter any_interconnect = boost::keep_all{};
VertexFilter bidders = [graph](V v) -> bool { return boost::get<Bidder>(&(graph)[v]); };
VertexFilter items = [graph](V v) -> bool { return boost::get<Item>(&(graph)[v]); };
FMap map_bidders = FMap(graph, any_interconnect, bidders);
FMap map_items = FMap(graph, any_interconnect, items);
auto iterator_bidder = boost::make_iterator_range(boost::vertices(map_bidders));
auto iterator_item = boost::make_iterator_range(boost::vertices(map_items));
auto t_start = now();
while (unassigned_bidders > 0) {
for (auto uncasted_bidder : iterator_bidder) {
if (gp.bidder2item[static_cast<int>(uncasted_bidder)] != -1) continue;
Bidder* bidder = boost::get<Bidder>(&graph[uncasted_bidder]);
// 1 Bid
int id_item1 = -1;
Weight val_item1 = -1;
Weight val_item2 = -1;
for (auto uncasted_item : iterator_item) {
Item* item = boost::get<Item>(&graph[static_cast<int>(uncasted_item)]);
Weight val = boost::get(boost::edge_weight_t(), graph, (boost::edge(uncasted_bidder, uncasted_item, graph)).first) - item->cost;
if (val > val_item1) {
val_item2 = val_item1;
val_item1 = val;
id_item1 = item->id;
}
else if (val > val_item2) {
val_item2 = val;
}
}
bidder->best_item = id_item1 + n;
bidder->val_first_best_item = val_item1;
bidder->val_second_best_item = val_item2;
// 2 Compete
Weight bid = bidder->val_first_best_item - bidder->val_second_best_item + eps;
auto best_item = boost::get<Item>(&graph[bidder->best_item]);
if (bid > best_item->high_bid) {
best_item->high_bid = bid;
best_item->high_bidder = bidder->id;
}
}
// 3 Assign
for (auto uncasted_item : iterator_item) {
Item* item = boost::get<Item>(&graph[uncasted_item]);
if (item->high_bid == -1) continue;
item->cost += item->high_bid;
if (gp.item2bidder[item->id] != -1) {
gp.bidder2item[gp.item2bidder[item->id]] = -1;
unassigned_bidders++;
}
gp.item2bidder[item->id] = item->high_bidder;
gp.bidder2item[gp.item2bidder[item->id]] = item->id;
unassigned_bidders--;
}
}
elapsed = now() - t_start;
}
Weight perform_au(Graph& graph, duration& elapsed) {
int n = int(boost::num_vertices(graph) / 2);
Weight total_cost_auction = 0;
auction_algorithm(graph, n, elapsed);
std::cout << "\nThe matching is: ";
for (int bidder = 0; bidder < n; ++bidder) {
std::cout << "(" << bidder << "," << graph[boost::graph_bundle].bidder2item[bidder] << ")";
int item = graph[boost::graph_bundle].bidder2item[bidder];
total_cost_auction += boost::get(boost::edge_weight_t(), graph, (boost::edge(bidder, item + n, graph)).first);
}
std::cout << "\n";
return total_cost_auction;
}
I have compared this to the vector implementation and notice that the latter is much faster than mine (however they return the same amount of total cost). Is it due to the complexity of the boost::get? If so, why is it so heavy?
I'm using the g++ compiler on a Ubuntu machine and to compile the application I run the following line in my console:
g++ -std=c++2a -o ../bin/app BipartiteGraph.cpp MaximumWeightedMatching.cpp Auction.cpp AuctionArray.cpp Main.cpp
I share the link of my github repository so you can have a look at the whole project.
PS: If you have any suggestions for speeding up the algorithm, that would be great!
UPDATE: 09/08/2022
Requirement: Make the auction algorithm generic like the style of the Boost Graph Library. This is the last implementation that I've made.
UPDATE: 10/08/2022
I've made a class that maintain the all stuff like it was before with the Bundle Properties:
UPDATE: 14/08/2022
Actual version
Weight perform_au(const Graph& graph, Duration& elapsed, int& n_iteration_au, bool verbose)
{
int n = int(boost::num_vertices(graph) / 2);
std::vector<int> assignments(n);
Auction<Graph, Weight> auction_problem(n);
auto t_start = now();
auction_problem.auction_algorithm(graph, assignments);
elapsed = now() - t_start;
std::cout << " Finished \nThe matching is: ";
for (int bidder = 0; bidder < n; ++bidder)
std::cout << "(" << bidder << "," << assignments[bidder] << ")";
std::cout << "\n";
if (verbose) auction_problem.printProprieties();
n_iteration_au = auction_problem.getNIterationAu();
return auction_problem.getTotalCost(graph);
}
#ifndef _AA_H
#define _AA_H
#include <vector>
#include <unordered_map>
#include <boost/graph/adjacency_list.hpp>
template<typename T>
using AdjacencyIterator = boost::graph_traits<T>::adjacency_iterator;
template<typename Graph, typename Type>
class Auction
{
private:
struct Bidder {
int best_item = -1;
double val_first_best_item = -1;
double val_second_best_item = -1;
};
struct Item {
double cost = 0;
int high_bidder = -1;
double high_bid = -1;
};
int n_iteration_au = 0;
int vertices = 0;
std::unordered_map<int, Bidder> unassigned_bidder;
std::unordered_map<int, Bidder> assigned_bidder;
std::unordered_map<int, Item> item_map;
bool is_assignment_problem(const Graph& graph);
void auctionRound(const Graph& graph, const double& eps, const auto& vertex_idMap);
public:
void auction_algorithm(const Graph& graph, std::vector<int>& ass);
int getNIterationAu();
Type getTotalCost(const Graph& graph);
void printProprieties();
Type getMaximumEdge(const Graph& graph);
void reset();
Auction(int vertices)
{
this->vertices = vertices;
for (int i : boost::irange(0, vertices))
{
this->unassigned_bidder.insert(std::make_pair(i, Bidder{}));
this->item_map.insert(std::make_pair(i, Item{}));
}
}
};
template<typename Graph, typename Type>
inline int Auction<Graph, Type>::getNIterationAu() { return n_iteration_au; }
template<typename Graph, typename Type>
Type Auction<Graph, Type>::getMaximumEdge(const Graph& graph)
{
Type max = 0;
typedef boost::graph_traits<Graph>::edge_iterator edge_iterator;
std::pair<edge_iterator, edge_iterator> ei = boost::edges(graph);
for (edge_iterator edge_iter = ei.first; edge_iter != ei.second; ++edge_iter)
if (boost::get(boost::edge_weight_t(), graph, *edge_iter) > max)
max = boost::get(boost::edge_weight_t(), graph, *edge_iter);
return max;
}
template<typename Graph, typename Type>
inline Type Auction<Graph, Type>::getTotalCost(const Graph& graph)
{
Type total_cost_auction = 0;
for (int bidder = 0; bidder < vertices; ++bidder)
total_cost_auction += boost::get(boost::edge_weight_t(), graph, (boost::edge(bidder, assigned_bidder[bidder].best_item + vertices, graph)).first);
return total_cost_auction;
}
template<typename Graph, typename Type>
bool Auction<Graph, Type>::is_assignment_problem(const Graph& graph)
{
for (auto v1 : boost::make_iterator_range(boost::vertices(graph)))
{
AdjacencyIterator<Graph> ai, a_end;
boost::tie(ai, a_end) = boost::adjacent_vertices(v1, graph);
if (ai == a_end) return false;
else
for (auto v2 : boost::make_iterator_range(ai, a_end))
if ((v1 < vertices && v2 < vertices) || (v1 > vertices && v2 > vertices))
return false;
}
return true;
}
template<typename Graph, typename Type>
inline void Auction<Graph, Type>::printProprieties()
{
for (auto& bidder : assigned_bidder)
std::cout << "|Bidder:" << bidder.first << "|Best item:" << bidder.second.best_item << "|Value first best item:" << bidder.second.val_first_best_item << "|Value second best item:" << bidder.second.val_second_best_item << "|\n";
for (auto& item : item_map)
std::cout << "|Item:" << item.first << "|Cost:" << item.second.cost << "|Higher bidder:" << item.second.high_bidder << "|Higher bid:" << item.second.high_bid << "|\n";
}
template<typename Graph, typename Type>
void Auction<Graph, Type>::auctionRound(const Graph& graph, const double& eps, const auto& vertex_idMap)
{
for (auto& bidder : unassigned_bidder)
{
int id_item1 = -1;
double val_item1 = -1;
double val_item2 = -1;
AdjacencyIterator<Graph> ai, a_end;
boost::tie(ai, a_end) = boost::adjacent_vertices(vertex_idMap[bidder.first], graph);
for (auto item : boost::make_iterator_range(ai, a_end)) // itero iniziando da quelli che hanno meno vertici?
{
double val = (boost::get(boost::edge_weight_t(), graph, (boost::edge(bidder.first, static_cast<int>(item), graph)).first)) // * (vertices))
- item_map[static_cast<int>(item) - vertices].cost;
if (val > val_item1)
{
val_item2 = val_item1;
val_item1 = val;
id_item1 = static_cast<int>(item) - vertices;
}
else if (val > val_item2) val_item2 = val;
}
bidder.second.best_item = id_item1;
bidder.second.val_second_best_item = val_item2;
bidder.second.val_first_best_item = val_item1;
double bid = bidder.second.val_first_best_item - bidder.second.val_second_best_item + eps;
if (item_map.find(bidder.second.best_item) != item_map.end())
{
if (bid > item_map[bidder.second.best_item].high_bid)
{
item_map[bidder.second.best_item].high_bid = bid;
item_map[bidder.second.best_item].high_bidder = bidder.first;
}
}
}
for (auto& item : item_map)
{
if (item.second.high_bid == -1) continue;
item.second.cost += item.second.high_bid;
int id_to_remove = -1;
for (auto& ass_bidr : assigned_bidder)
{
if (ass_bidr.second.best_item == item.first)
{
id_to_remove = ass_bidr.first;
break;
}
}
if (id_to_remove != -1)
{
unassigned_bidder.insert(std::make_pair(id_to_remove, assigned_bidder[id_to_remove]));
assigned_bidder.erase(id_to_remove);
}
assigned_bidder.insert(std::make_pair(item.second.high_bidder, unassigned_bidder[item.second.high_bidder]));
unassigned_bidder.erase(item.second.high_bidder);
}
}
template<typename Graph, typename Type>
void Auction<Graph, Type>::auction_algorithm(const Graph& graph, std::vector<int>& ass)
{
if (!is_assignment_problem(graph)) throw("Not an assignment problem");
auto vertex_idMap = boost::get(boost::vertex_index, graph);
double eps = static_cast<double>(1.0 / (vertices + 1));
while (unassigned_bidder.size() > 0)
{
auctionRound(graph, eps, vertex_idMap);
n_iteration_au += 1;
}
for (auto& a : assigned_bidder) ass[a.first] = a.second.best_item;
}
#endif
Why would it not be heavy.
Again,
FMap map_bidders = FMap(graph, any_interconnect, bidders);
FMap map_items = FMap(graph, any_interconnect, items);
Just "wishing" things to be a property map doesn't make them so.
Also, your filter predicates:
EdgeFilter any_interconnect = boost::keep_all{};
VertexFilter bidders = [graph](V v) -> bool { return boost::get<Bidder>(&(graph)[v]); };
VertexFilter items = [graph](V v) -> bool { return boost::get<Item>(&(graph)[v]); };
FMap map_bidders = FMap(graph, any_interconnect, bidders);
FMap map_items = FMap(graph, any_interconnect, items);
They...
copy the entire graph(!), twice
uselessly get<> a variant element, just to discard it and return bool
Slightly better:
VertexFilter bidders = [&graph](V v) -> bool {
return graph[v].which() == 0;
};
VertexFilter items = [&graph](V v) -> bool {
return graph[v].which() == 1;
};
FMap map_bidders = FMap(graph, {}, bidders);
FMap map_items = FMap(graph, {}, items);
But it's all kind of useless. I'm not suprised this stuff takes time, because you know your graph is structured (N bidders)(N items), so
auto iterator_bidder = boost::make_iterator_range(vertices(map_bidders));
auto iterator_item = boost::make_iterator_range(vertices(map_items));
CouldShould just be:
auto [b,e] = vertices(graph);
auto iterator_bidder = boost::make_iterator_range(b, b + n);
auto iterator_item = boost::make_iterator_range(b + n, e);
And even those are overkill, since your vertex descriptor is integral anyways:
auto const bidders = boost::irange(0, n);
auto const items = boost::irange(n, 2 * n);
I'll read some more later (family time first), because I'm already noticing more (e.g. why is listS used as the edge container selector?).
Will post here when done.

C++: How to iterate through a double pointer pointing to an array of pointers

In the following piece of code, I am iterating through a pointer to an array of pointers to TreeNode objects. Below is my code where I iterate through the array:
TreeNode* childListPointer = *currNode->children;
for (TreeNode* currChild = childListPointer; currChild != NULL; currChild = ++childListPointer) {
std::cout << "Iteration" << endl;
}
And below is the code of my TreeNode struct:
typedef struct TreeNode {
int key;
int val;
bool flag;
int num_children;
TreeNode **children;
} TreeNode;
However, my code keeps getting stuck an infinite loop, even when the length of the array is a small number (e.x. 4 or 5).
Note: The autograder system does not allow me to modify the TreeNode struct.
Your array is a size and count.
int num_children;
TreeNode **children;
Based off that, you can make a simple range adapter for for(:) loops:
template<class It>
struct range {
It s, f;
It begin() const { return s; }
It end() const { return f; }
range(It b, It e):s(b),f(e) {}
range(It b, std::ptrdiff_t count):range(b, b+count) {}
};
now, just:
for(TreeNode* child : range{ currNode->children, currNode->num_children })
{
std::cout << "Iteration" << endl;
}
Prior to c++17 you need a make_range:
template<class It>
range<It> make_range( It b, It e ) { return {b,e}; }
template<class It>
range<It> make_range( It b, std::ptrdiff_t c ) { return {b,c}; }
for(TreeNode* child : make_range( currNode->children, currNode->num_children ))
{
std::cout << "Iteration" << endl;
}
because "deduction guides" where added in c++17.
And you are done. You can now iterate over the children without doing any pointer arithmetic and getting confused.
...
If you are stuck in c++03 you can do:
for (int i = 0; i < currNode->num_children; ++i)
{
TreeNode* child = currNode->children[i];
std::cout << "Iteration" << endl;
}
or
TreeNode** it = currNode->children;
TreeNode** end = it+currNode->num_children;
for (; it != end; ++it)
{
TreeNode* child = *it;
std::cout << "Iteration" << endl;
}
which is almost exactly what the range version compiles down to.

Can I get default template argument from template specialization with clang AST?

I want to get default template argument from a template specialization with clang AST, but can find no way.
Can anyone help me?
template<typename TT0>
struct DefaultArg
{
typedef char TypeT;
};
template<typename TT0,
typename TT1 = typename DefaultArg<TT0>::TypeT >
struct Template0
{
};
Template0<int> s; // Is there any way to get 'DefaultArg<int>::TypeT'
// ( neither DefaultArg<TT0>::TypeT nor 'char' )
// as default template argument
// for this template specialization?
AST dump for the sample
Short answer: not to my knowledge.
Work around solution...
Here is example code that does the trick:
(it only works for depth=0)
bool CheckSpecializedTemplate(const clang::QualType& Type)
{
// ignore types that are not class or struct records
if (!Type->isRecordType() || !Type->isStructureOrClassType())
return false;
// get the underlying record and make sure it is a
// specialization of a template type
const clang::CXXRecordDecl* Record = Type->getAsCXXRecordDecl();
if (Record->getKind() != clang::Decl::Kind::ClassTemplateSpecialization)
return false;
return true;
}
bool TrySubstitutionPrint(
const clang::TemplateParameterList* TemplateList,
const clang::TemplateArgumentList& ArgumentsList,
const clang::QualType& Type)
{
//
// Hack to patch in the type substitutions
// (AST doesn't seem to preserve dependent template specialization)
//
auto& out = llvm::outs();
// from the dependent type, get the nested type or return
const clang::Type* Ptr = Type.getTypePtr();
if (Ptr->getTypeClass() != clang::Type::TypeClass::DependentName)
return false;
const clang::DependentNameType* DnPtr =
static_cast<const clang::DependentNameType*>(Ptr);
const clang::NestedNameSpecifier* Nns = DnPtr->getQualifier();
if (!Nns) return false;
if (Nns->getKind() != clang::NestedNameSpecifier::SpecifierKind::TypeSpec)
return false;
const clang::Type* NestedPtr = Nns->getAsType();
if (NestedPtr->getTypeClass() != clang::Type::TypeClass::TemplateSpecialization)
return false;
const clang::TemplateSpecializationType* TsPtr =
static_cast<const clang::TemplateSpecializationType*>(NestedPtr);
const clang::TemplateDecl* Temp = TsPtr->getTemplateName().getAsTemplateDecl();
out << DnPtr->getKeywordName(DnPtr->getKeyword()).str();
out << " " << Temp->getNameAsString() << "<";
// match the args to their respective parameters
const clang::TemplateParameterList* List = Temp->getTemplateParameters();
bool Multi = false;
for (auto Token = List->begin(); Token != List->end(); Token++) {
if (Multi) out << ", "; else Multi = true;
out << (*Token)->getNameAsString();
// brute force search
int Index = 0;
for (auto T2 = TemplateList->begin(); T2 != TemplateList->end(); T2++) {
if ((*T2)->getNameAsString() == (*Token)->getNameAsString()) {
out << " = " << ArgumentsList[Index].getAsType().getAsString();
break;
}
Index++;
}
}
out << ">::";
// print the dependent type name
const clang::IdentifierInfo* identifier = DnPtr->getIdentifier();
out << identifier->getName().str();
return true;
}
bool VisitVarDecl(clang::VarDecl* Decl)
{
auto& out = llvm::outs();
clang::QualType Type = Decl->getType();
// let's only look for variables with name "s"
auto varname = Decl->getNameAsString();
if (varname != "s") return true;
// we only want specialized templates
if (!CheckSpecializedTemplate(Type)) return true;
// convert the record to a specialization and
// get the underlying template decl
const clang::CXXRecordDecl* Record = Type->getAsCXXRecordDecl();
const clang::ClassTemplateSpecializationDecl* Special =
static_cast<const clang::ClassTemplateSpecializationDecl*>(Record);
const clang::ClassTemplateDecl* Template = Special->getSpecializedTemplate();
// iterate over the list of template parameters and print them out
const clang::TemplateArgumentList& ArgsList =
Special->getTemplateArgs();
const clang::TemplateParameterList* TemplateList =
Template->getTemplateParameters();
int Index = 0;
for (clang::TemplateParameterList::const_iterator
TemplateToken = TemplateList->begin();
TemplateToken != TemplateList->end(); TemplateToken++)
{
switch ((*TemplateToken)->getKind()) {
case clang::Decl::Kind::TemplateTemplateParm: {
const clang::TemplateArgument& c = ArgsList[Index];
out << "class = " << c.getAsType().getAsString();
} break;
case clang::Decl::Kind::TemplateTypeParm: {
const clang::TemplateTypeParmDecl* ttpd =
static_cast<const clang::TemplateTypeParmDecl*>(*TemplateToken);
if (ttpd->hasDefaultArgument()) {
clang::QualType DefaultArg = ttpd->getDefaultArgument();
if (!TrySubstitutionPrint(TemplateList, ArgsList, DefaultArg))
out << DefaultArg.getAsString() << "+";
}
else out << "template " << ttpd->getNameAsString();
const clang::TemplateArgument& c = ArgsList[Index];
out << " = " << c.getAsType().getAsString();
} break;
}
out << "\n";
Index++;
}
// All done!
out << "\n";
return true;
}
The output for your code snippet would be
template TT0 = int
typename DefaultArg<TT0 = int>::TypeT = char

What is the purpose of std::rank?

I just ran into std::rank and I don't really understand what it could be used for. I understand what it does, but can someone please give me a few use cases for it? I wasn't able to find anything useful on a search here.
Nice question.
I'm trying to learn C++11, so I could write something silly but ... suppose you want find the maximum value in a multidimensional array.
I tried to answer this question with std::rank (and SFINAE)
#include <iterator>
#include <iostream>
#include <type_traits>
template <typename X,
typename = typename std::enable_if<0U == std::rank<X>::value>::type>
X maxRank (X const & x)
{ return x; }
template <typename X,
typename = typename std::enable_if<0U != std::rank<X>::value>::type>
typename std::remove_all_extents<X>::type maxRank (X const & x)
{
auto it = std::begin(x);
auto ret = maxRank(*it);
for ( ; it != std::end(x) ; ++it )
{
auto val = maxRank(*it);
if ( val > ret )
ret = val;
}
return ret;
}
int main ()
{
int a0 = 12;
short a1[] = { 23, 7, 42, -19, 0, 95 };
unsigned a2[][2] = { {8U, 9U}, {0U, 77U}, {11U, 9U}, {5U, 3U} };
long a3[][3][2] = { { {123L, 3L}, {-45L, 77L}, {-12L, 678L} },
{ {1L, -54L}, {23L, 99L}, {56L, 1234L} },
{ {-4L, -12L}, {1L, 0L}, {122L, 19L} },
{ {2L, 23L}, {55L, 19L}, {2L, 99L} } };
std::cout << "maxRank a0 = " << maxRank(a0) << '\n';
std::cout << "maxRank a1 = " << maxRank(a1) << '\n';
std::cout << "maxRank a2 = " << maxRank(a2) << '\n';
std::cout << "maxRank a3 = " << maxRank(a3) << '\n';
return 0;
}

Object values altered after return from function

PART OF A HOMEWORK PROBLEM
I have a list of objects, and my goal is to try and find if an object X is present in that list (I am interested only in the first occurrence of that object). My code seems to work fine for the most part, but I have this strange error where the value of only 1 particular object is being modified after it is returned from a function.
I added 10 objects to the list with values 0 through 3. When I search for any number except 0, (./a.out 1 OR ./a.out 2 and so on)I get the right output. But when I search for 0(./a.out 0), the findInList() prints the correct result, but the main() prints the value 18 (which is not even present in the list).
I am attaching the full source code here in case someone wants to compile it and try it out. I am also attaching the gdb step through I did.
SOURCE:
#include <iostream>
#include <string>
#include <functional>
#include <list>
using namespace std;
class Page {
public:
int pgnum; // page number
union {
int lfu_count;
int lru_clock:1; // can only be 0/1
int lru_ref8:8; // we only need 8 bits
};
public:
// Constructors
Page(int num) { pgnum = num; }
Page() {}
// Operator overloading
bool operator== (const Page &p) const {
if(p.pgnum == pgnum)
return true;
else
return false;
}
bool operator!= (const Page &p) const {
return !(p==*this);
}
};
ostream & operator<<(ostream & os, const Page &p) {
os << "Page number: " << p.pgnum;
return os;
}
// Think of this as an equivalent to equals in Java (IT IS NOT, JUST IMAGINE)
struct PageNumber: public binary_function< Page, Page, bool > {
bool operator () ( const Page &p1, const Page &p2 ) const {
return p1 == p2;
}
};
// Function to find an object in any list given an Operation
template <class Operation, class T>
T* findInList( list<T> fullList, T obj, const Operation &op ) {
T* ret = NULL;
typename list<T>::iterator it = fullList.begin();
it = find_if( it, fullList.end(), bind2nd( op, obj ) );
if( it != fullList.end() ) {
cout << "Found obj in list: " << *it << endl;
ret = &(*it); // not the same as it (which is of type iterator)
}
return ret;
}
int main( int argc, char **argv ) {
Page page_to_find;
list<Page> frames;
if( argc != 2 ) {
cout << "Please enter 1 and only 1 argument" << endl;
exit(-1);
}
page_to_find.pgnum = atoi(argv[1]);
Page *p = new Page[10];
for( int i=0; i<10; i++ ) {
p[i].pgnum = i%4;
frames.push_back(p[i]);
}
list<Page>::iterator it_frames = frames.begin();
while( it_frames != frames.end() ) {
cout << "Page in frames: " << *it_frames << endl;
it_frames++;
}
Page* pg = findInList( frames, page_to_find, PageNumber() );
if( pg != NULL )
cout << "Found page: " << *pg << endl;
delete[] p;
return 0;
}
You're returning the address of an object in a list that is pushed into the parameter list by value. Thus it is undefined behavior. Consider changing the parameter of the list in findInList to a reference.
// note reference type change in parameter list.
template <class Operation, class T>
T* findInList( list<T>& fullList, T obj, const Operation &op ) {
T* ret = NULL;
typename list<T>::iterator it = fullList.begin();
it = find_if( it, fullList.end(), bind2nd( op, obj ) );
if( it != fullList.end() ) {
cout << "Found obj in list: " << *it << endl;
ret = &(*it); // not the same as it (which is of type iterator)
}
return ret;
}