In a file AddressSanitizer.cpp there is a function AddressSanitizer::instrumentStoreInstruction(...)
void AddressSanitizer::instrumentStoreInstruction(StoreInst *S, Instruction *I) {
assert(nullptr != S);
assert(nullptr != I);
Value* V = S->getValueOperand();
assert(nullptr != V);
Value* P = S->getPointerOperand();
assert(nullptr != P);
DEBUG(dbgs() << "ASAN Store Value : " << " " <<*V << "\n");
DEBUG(dbgs() << "ASAN Store Pointer" << " " <<*P << "\n");
Value* vL = 0;
if (isa<Instruction>(V)) {
vL = getStoreInstructionValueShadowBit(V, I);
handleStorePointerOperand(P, I, vL);
} else if (isa<ConstantExpr>(V)) {
instrumentConstantExprStoreInstruction(V, P, I);
} else if (isa<ConstantInt>(V) || isa<ConstantFP>(V)) {
//TODO: need to change to ConstantData after LLVM porting
instrumentConstantIntStoreInstruction(V, P, I);
}
}
How to check is store Instruction value operand is a function parameter.
You can use isa<Argument>(V) to check if a value V is a function argument. Documentation for the Argument class can be found here: http://llvm.org/doxygen/classllvm_1_1Argument.html.
Related
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
I'm trying to display a vector contents named l_anMarking, but I'm getting this error message:
error : expression must have class type while trying to match the argument list '(std::ostream, std::vector<long,std::allocator<_Ty>>)
I don't understand why I'm having this error. This is my code:
Header file:
class SPSIM_EXPORT ParaStochSimulator : public StochasticSimulator
{
private:
protected:
VectorLong m_anCurrentMarking;
long m_nMinTransPos;
public:
void first_reacsimulator();
void ParaStochSimulator::broad_cast(long);
}
cpp:
void ParaStochSimulator::first_reacsimulator()
{
if (mnprocess_id==0)
{
broad_cast(m_anCurrentMarking);
}
}
void ParaStochSimulator::broad_cast(long j)
{
std::cout << "i'm broad_casting" << std::endl;
double val;
//Get manipulated places
VectorLong l_nMinplacesPos = (*m_pcTransitionsInfo)[j]->GetManipulatedPlaces();
double* l_anMarking=new double [l_nMinplacesPos.size()];
//l_anMarking.clear();
//double var = l_nMinplacesPos.size();
int i = 0;
for (auto lnpos : l_nMinplacesPos)
{
val = m_anCurrentMarking[lnpos];
l_anMarking[i++] = val;
}
std::vector<VectorLong>::iterator it;
for (it = l_anMarking.begin(); it < l_anMarking.end(); it++) //here
{
std::cout << *it << std::endl;
}
MPI_Bcast(&l_anMarking, sizeof l_nMinplacesPos, MPI_DOUBLE, 0, MPI_COMM_WORLD);
delete[] l_anMarking;
}
int main()
{
((spsim::ParaStochSimulator*)l_pcStochSolver)->first_reacsimulator();
}
Your l_anMarking variable is declared as a raw double* pointer, but you are trying to treat it as an STL container by calling begin() and end() on it. Thus the compiler error.
You have two choices:
Change the second for loop to use indexes instead of iterators.
for (int k = 0; k < i; ++k)
{
std::cout << l_anMarking[k] << std::endl;
}
Change l_anMarking to be a std::vector<double> instead (and adjust MPI_Bcast()) accordingly):
std::vector<double> l_anMarking;
l_anMarking.reserve(l_nMinplacesPos.size());
for (auto lnpos : l_nMinplacesPos)
{
val = m_anCurrentMarking[lnpos];
l_anMarking.push_back(val);
}
for (auto marking : l_anMarking)
{
std::cout << marking << std::endl;
}
The compiler error is referring to not being able to print the VectorLong to std::cout
std::vector<VectorLong>::iterator it;
for (it = l_anMarking.begin(); it < l_anMarking.end(); it++) //here
{
std::cout << *it << std::endl; // need an operator<< for your VectorLong
}
You should add something like this:
std::ostream & operator<<(std::ostream &os, const VectorLong& v)
{
os << "VectorLong: ";
for (const auto &l : v)
os << l << " ";
return os;
}
I cannot figure out why the algorithm results in an infinite loop. I am trying to sort the vector according to the final price. The pivot always stays the same. Maybe the problem is with the swapping of the objects
Motorbike findPivotPricee(vector<Motorbike*>& available, int left, int right)
{
int center = (left + right) / 2;
if (available[center]->finalPrice() < available[left]->finalPrice())
{
swap(*available[left], *available[center]);
}
if (available[right]->finalPrice()< available[left]->finalPrice())
{
swap(*available[left], *available[right]);
}
if (available[right]->finalPrice() < available[center]->finalPrice())
{
swap(*available[center], *available[right]);
}
Motorbike pivot = *available[center];
swap(*available[center], *available[right - 1]);
return pivot;
}
void quickSortMotorbikeByPrice(vector<Motorbike*>& available, int left, int right)
{
int i = left;
int j = right-1;
Motorbike pivot = findPivotPricee(available, left, right);
cout << pivot.finalPrice() << endl;
while (i < j)
{
while (available[i]->finalPrice() < pivot.finalPrice())
{
i++;
}
while (available[j]->finalPrice() > pivot.finalPrice())
{
j--;
}
if (i <= j)
{
swap(*available[i], *available[j]);
i++;
j--;
}
else {
break;
}
}
swap(*available[i], *available[right - 1]);//restore the pivot
if (left < right) {
if (left<j) quickSortMotorbikeByPrice(available, left, j);
if (right>i) quickSortMotorbikeByPrice(available, i, right);
}
}
void quickSortMotorbikeByPrice(vector<Motorbike*>& available)
{
quickSortMotorbikeByPrice(available, 0, available.size() - 1);
}
Often, algorithms from wikipedia, e.g. the quicksort algorithms are hard to transform into a working implementation because they fail to point out the assumed programming model implied by the given algorithm. For example, if it is a 0 based or a 1 based array and that they assume that the indices used are signed not unsigned integers.
Then, people start trying to use those algorithms, here, for example in C++ and run into all sorts of problems. Quite a waste of time... And from looking at the code given in the question, I assume the author of the question tried to use info from wikipedia...
Since this is obviously homework, impress your teacher and use the code below. Quicksort is tricky to get right and it can take quite a while to find out if you should write lo = left + 1 or lo = left etc.
#include <cstdint>
#include <memory>
#include <vector>
#include <iostream>
#include <cassert>
template <class X>
void vswap(std::vector<X>& v, size_t i1, size_t i2)
{
X temp = v[i1];
v[i1] = v[i2];
v[i2] = temp;
}
template <typename X>
std::ostream& operator<<(std::ostream& stm, const std::vector<X>& v)
{
stm << "[|";
size_t i = 0;
for (auto& x : v)
{
if (0 == i)
stm << x;
else
stm << "; " << x;
i++;
}
stm << "|]";
return stm;
}
template <typename X>
std::ostream& operator<<(std::ostream& stm, const std::vector<X*>& v)
{
stm << "[|";
size_t i = 0;
for (auto& x : v)
{
if (0 == i)
if (nullptr == x) stm << "nullptr"; else stm << *x;
else
if (nullptr == x) stm << "; nullptr"; else stm << "; " << *x;
i++;
}
stm << "|]";
return stm;
}
template <class X, class Predicate>
size_t partition(std::vector<X> & v, Predicate p, size_t left, size_t right)
{
size_t boundary = left;
X x = v[boundary];
for (size_t i = left; i < right; i++)
{
if (p(v[i], x))
{
vswap(v, boundary, i);
boundary++;
}
}
return boundary;
}
template<class X, class Predicate>
void mysort(std::vector<X> & v, Predicate p, size_t left, size_t right)
{
//std::cout << "mysort: " << v << " " << left << " " << right << std::endl;
if ((right - left) > 1)
{
size_t boundary = partition(v, p, left, right);
//std::cout << "boundary = " << boundary << std::endl;
mysort(v, p, left, boundary);
mysort(v, p, boundary == left ? boundary + 1 : boundary, right);
}
}
class Motorbike
{
size_t m_id;
int32_t m_finalPrice;
public:
Motorbike()
: m_id(0)
, m_finalPrice(0)
{}
Motorbike(size_t id, int32_t finalPrice)
: m_id(id)
, m_finalPrice(finalPrice)
{}
void Id(size_t id)
{
m_id = id;
}
size_t Id() const
{
return m_id;
}
void Price(int32_t price)
{
m_finalPrice = price;
}
int32_t Price() const
{
return m_finalPrice;
}
};
std::ostream& operator<< (std::ostream& stm, const Motorbike& bike)
{
stm << "(" << bike.Id() << ", " << bike.Price() << ")";
return stm;
}
std::vector<Motorbike> randomBikes(size_t count, int32_t lowPrice = 100, int32_t highPrice = 1000)
{
std::vector<Motorbike> result;
result.resize(count);
for (size_t i = 0; i < count; i++)
{
result[i].Id(i);
result[i].Price(lowPrice + rand() * (highPrice - lowPrice) / RAND_MAX);
}
return result;
}
std::vector<Motorbike*> bikePointers(std::vector<Motorbike> & bikes)
{
std::vector<Motorbike*> result;
result.resize(bikes.size());
for (size_t i = 0; i < bikes.size(); i++)
{
result[i] = &bikes[i];
}
return result;
}
int main()
{
//_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF);
//_CrtDumpMemoryLeaks();
//{
//{
// std::vector<int32_t> data = { 3, 5, 1, 4, 2, 0 };
// std::cout << "original: " << data << std::endl;
// mysort(data, [](int32_t a, int32_t b) -> bool {return a < b;}, 0, data.size());
// std::cout << "sorted? " << data << std::endl;
//}
//std::cout << "--------------------------------------------------------" << std::endl;
//{
// std::vector<int32_t> data = { 3, 6, 1, 4, 2, 0, 5 };
// std::cout << "original: " << data << std::endl;
// mysort(data, [](int32_t a, int32_t b) -> bool {return a < b;}, 0, data.size());
// std::cout << "sorted? " << data << std::endl;
//}
for(size_t run = 0; run < 10; run++)
{
auto bikes = randomBikes(5+run%2);
auto bikes_p = bikePointers(bikes);
std::cout << "original: " << bikes_p << std::endl;
mysort(bikes_p, [](const Motorbike* m1, const Motorbike* m2)-> bool { return m1->Price() < m2->Price(); }, 0, bikes_p.size());
std::cout << "sorted? " << bikes_p << std::endl;
std::cout << "--------------------------------------------------------" << std::endl;
}
//}
//_CrtDumpMemoryLeaks();
return 0;
}
I'm working for my project of the end of the year with c++ language and I'm really stressed because I have 5 days in this error and there is no enough time . I hope you help me :
the error is:
no match for 'operator<<' in 'std::operator<< <std::char_traits<char> >((* &(& std::operator<< <std::char_traits<char> >((* & tempout.std::basic_ofstream<char>::<anonymous>), ((const char*)"Node ")))->std::basic_ostream<_CharT, _Traits>::operator<< <char, std::char_traits<char> >(i.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator-><Lattice<std::pair<std::vector<int>, std::vector<int> > >::Node*
the line of the error is : tempout<<"Node " << i->index << ": " <<i->c<<endl; and more sepifically in i->c
My code is the following:
//template named N
template<typename N>
//class latice that contains structure Node and other attribytes
class Lattice {
public:
int count; //count is incremented at every Node insertion in the latticeSet
typedef std::pair<std::vector<int>, std::vector<int> > Concept;
// Node is a set of concepts
//a latticeSet is a set of Node
struct Node {
int index;
typedef std::pair<std::vector<int>, std::vector<int> > Concept;
Node() {}; //constructor
Node(const N& con, int i) : c(con), index(i) {};
N c;
bool operator== (const Node& n) const { return c.first == n.c.first; }
std::pair<std::vector<int>,std::vector<int> > lowerUpperNeighbors;
};
std::vector<Node> latticeSet;//a set of Node
int last_position_cached;
bool was_insert_called;
Lattice() : count(0), last_position_cached(0), was_insert_called(false) {} //constructor
friend ostream& operator<< ( std::ostream& out,const Concept &c) {
out << "{";
if (c.first.size()!=0) {
for(std::vector<int>::const_iterator j = c.first.begin(); j < c.first.end() - 1; ++j)
out << *j << ", ";
out << *(c.first.end() - 1);
}
out << "}, {";
if (c.second.size()!=0) {
for(vector<int>::const_iterator j = c.second.begin(); j < c.second.end() - 1; ++j)
out << *j << ", ";
out << *(c.second.end() - 1);
}
out << "}";
return out;
}
/* The following method is a combination of both insert(x, L) and lookup(x, L) from the FCA Lattice Algorithm.
insertLookup takes a reference to a concept x, and c as input.
Concept x is an upper neighbor of c found by Neighbors, and c is the concept in which x was found to be its upper neighbor.
First, latticeSet is searched for the upper neighborx of c, and if it is not found then it is inserted in the lattice (same fashion as insert).
Next, the lattice is checked if it contains concept c, and if it does then the method returns false due to some unexpected case.
This condition is checked if insert was called, and if the last position of a concept cached by next is not equal to c.
Then, the lattice is searched for concept c in order to add its upper neighbor x.
Finally, concept x/c adds concept c/x as its lower/upper neighbor, respectively.
This method returns true if concept x was inserted in the lattice and c was added to its upper neighbors.
*/
bool insertLookup(const N& x, const N& c) {
std::vector<Node> latticeSet;
typename vector<Node>::iterator x_pos = find(latticeSet.begin(), latticeSet.end(), Node(x, count));
if (x_pos == latticeSet.end()) {
latticeSet.push_back(Node(x, count++));
x_pos = latticeSet.end() - 1;
}
typename vector<Node>::iterator c_pos;
if (was_insert_called && !(latticeSet[last_position_cached].c.first == c.first)) {
c_pos = find(latticeSet.begin(), latticeSet.end(), Node(c, count));
if (c_pos == latticeSet.end()) {
return false;
}
}
else
c_pos = latticeSet.begin() + last_position_cached;
x_pos->lowerUpperNeighbors.first.push_back(c_pos->index);
c_pos->lowerUpperNeighbors.second.push_back(x_pos->index);
return true;
}
//This method inserts a concept in the concept lattice.
bool insert(const N& c) {
latticeSet.push_back(Node(c, count++));
was_insert_called = true;
return true;
}
bool next(const N& c, N& output) {
typename vector<Node>::iterator pos = find(latticeSet.begin(), latticeSet.end(), Node(c, 0));
if (pos == latticeSet.end() || ++pos == latticeSet.end())
return false;
output = pos->c;
last_position_cached = pos - latticeSet.begin();
return true;
}
/* The following method is used to generate the required input file for graphplace.
printGraphplaceInput takes a reference to an output file stream out, and a flag (with a default value of zero).
First an output file stream tempout is in- stantiated with a file called “explain.graph” (see section 4.2).
If the flag passed is zero, then each Node’s concept of the latticeSet is printed to the lattice output file out;
else if the flag passed equals one, then each Node’s unique index number of the latticeSet is printed to the lattice output file out.
During the creation of the lattice output file, “explain.graph” is created by writing each Node index and its corresponding concept to tempout.
This method returns nothing.
*/
void printGraphplaceInput(ofstream& out, int flag = 1) {
ofstream tempout("explain.graph");
for (typename std::vector<Node>:: iterator i = latticeSet.begin(); i!=latticeSet.end();++i) {
//the error is here in i->c it doesn't work .and the error is that na match for operator<< and i didi'nt find a solution
tempout << "Node " << i->index << ": " << i->c <<endl;
out << "(";
if(flag == 0) {
cout << i->index << endl;
}
else if(flag == 1) {
out << i->index;
}
out << ") " << i->index << " node" << endl;
for (typename vector<int>::iterator j = i->lowerUpperNeighbors.second.begin(); j < i->lowerUpperNeighbors.second.end();++j)
out << *j << " " << i->index << " edge" << endl;
}
};
//get the size of the lattice
unsigned int getLatticeSize() {
return latticeSet.size();
}
void LatticeAlgorithm(const Context& GMI, Lattice<Concept>& L) {
vector<int> temp;
Concept c;
GMI.objDPrime((const vector<int>&) temp, c.first);
GMI.objPrime((const vector<int>&) temp, c.second);
L.insert(c);
neighbors n;
vector<Concept> neighborSet;
do {
n.Neighbors(c, GMI, neighborSet);
for(vector<Concept>::const_iterator x = neighborSet.begin(); x < neighborSet.end(); ++x) {
L.insertLookup(*x, c);
}
}
while(L.next(c, c));
}
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;
}