I'm relatively new to programming and I did really well in my introductory class. However, as we are starting to get into the more advanced concepts of C++, I'm becoming more and more lost. I'm having a problem with a lab assignment, I hope you guys can help!
Write a generic list class called GenericList. The class should use a vector and be able to >be created with any type name. The class should have the following members:
A simple constructor
add(item) - add the item to the list
grabSmallest() - find, return and remove the smallest item in the list
Here is what I have so far, I believe it is at least set up correctly:
EDIT
This is what I have after the corrections that have been suggested, I've ran into a different problem now, though. Here is the revised code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template<typename T>
class GenericList
{
public:
GenericList();
void add(T value);
T grabSmallest();
private:
vector<T> listVector;
};
template<typename T>
GenericList<T>::GenericList()
{
}
template<typename T>
void GenericList<T>::add(T value)
{
listVector.push_back(value);
}
template<typename T>
T GenericList<T>::grabSmallest()
{
int smallest = listVector[0];
for (int i = 0; i < listVector.size(); i++)
{
if (listVector[i] < smallest)
{
smallest = listVector[i];
}
}
}
int main (){
GenericList<int> myList;
myList.add(10);
myList.add(5);
myList.add(20);
myList.add(15);
for(int i=0;i<4;i++)
cout << myList.grabSmallest() << " ";
}
I'm now having problems with my for loop in the grab function. Apparently, the compiler is putting random numbers into the vector.
Where is the last?
Even you have the last,
template<typename T>
void GenericList<T>::add(const T &value)
{
listVector[last++] = value; // <- should it be last++ or ++last?
}
or do you mean:
template<typename T>
void GenericList<T>::add(const T &value)
{
listVector.push_back(value)
}
BTW, With vector, you dont need the last field. It's kept in the vector: ` vector.size(). But why wrap vector when you could just use vector directly?
if you want the just want the smallest, priority_queue will do.
As gongzhitaao said, that line is not liking you because you never declare last and thus the compiler doesn't know what to do with it. as they said, you need to use push_back to solve that problem.
But you also need to solve another problem: what happens if they don't use int as their type? What if they want the "least" member of a custom class? You need to change this:
vector<int> listVector;
to this
vector<T> listVector;
So that the vector picks up the custom type that the template parameter T is specifying.
For grabSmallest I suggest you use some type of search to determine which element is the smallest, such as picking the first element, then looping through after that to see if each subsequent one is smaller or not. If it is, take that as your value, and loop. If not, just keep going. Whichever is left over at the end is smallest. But remember to use T as your type all the way through. Sorting it on every insert isn't necessary with this method.
As this is homework I didn't want to give you 100% of the answer with code, but hopefully the preceding paragraph is enough to get you going.
Edit: figured it out. Try www.codepad.org and run your code through it.
Basically, two errors in your grabSmallest() method.
It should be T smallest = listVector[0] not int. You should also have a "guard" that returns a default value (or throws an exception) if the list is empty.
grabSmallest() is supposed to return a value, but you forgot to. So your compiler is apparently way too forgiving, and didn't flag that as an error. Put return smallest as the last line of the method, just after the for loop.
Related
I'm trying to build a tree-like structure in C++ and I found out about initializer_list and tried to implement it as part of my code. I want the code to be able to create an object from a set of properties, be able to apply some methods and then append at the end an array of children.
So I came up (after a lot of tries and failure) with this:
#include <vector>
#include <initializer_list>
struct Branch
{
// Branch properties
int val;
std::vector<Branch> data;
Branch(int i): val(i) {}
Branch& operator=(std::initializer_list<Branch> list)
{
data = list;
return *this;
}
// Some function with specific behaviour
Branch& bar() {
return *this;
}
};
int main()
{
auto Main = Branch(1).bar() = {
Branch(2) = {
Branch(4)
},
Branch(3).bar(),
};
return Main.val;
}
As you can see, in my code I first pass the int property and then (sometimes) call a function depending on whether I want some specific traits for that branch or not. Then I attach a list for its children.
Now, I know that there are probably many things wrong with my code. For once I wanted to pass "Branch&" as type to the initializer_list (and vector) so it does not create a copy but then the compiler said no operator "=" matches these operands inside the main function.
So, here is my question. Is there a way to solve this? Maybe a workaround to pass a reference... Or maybe another implementation with similar effects.
I also tried with std::array instead of vector but it seems like they are not compatible.
I am new in C++. I created a cpp and a header file. Here is the header file:
class LISCH{
public:
class lisch_entry{
public:
bool valid;
int link;
int data;
lisch_entry(){
valid = false;
}
};
vector<lisch_entry> data_vec;
public:
LISCH(int);
void insert(int);
};
In cpp file , i need to access that data_vec vector in insert function but i couldn't do it because it's my first time coding in C++. Here is the cpp file:
#include "lisch.h"
#include <iostream>
using namespace std;
LISCH::LISCH(int table_size){
table_size=10;
int x=5;
}
void LISCH::insert(int new_data){
lisch_entry entry;
int add=new_data%11;
if(LISCH.data_vec[add] == NULL) //here i need to acces data_vec
{
}
data_vec.insert(add,new_data); //and also here
}
How can i manage to do that? I need to check if a specific position of the vector is empty or not.
There are quite a few of things wrong with code, probably for lack of planning or formulating the desired effect.
using namespace std; // never do this in real programs.
// Even some tests may fail accidently.
LISCH::LISCH(int table_size){
table_size=10; // those are local variables, why assigning values to them?
int x=5;
}
data_vec is defined as a vector of lisch_entry:
vector<lisch_entry> data_vec;
The you out of blue access element of type lisch_entry with index add. Did you allocate that many elements already? It may not exist at all, the program would crash:
if(LISCH.data_vec[add] == NULL)
An instance lisch_entry cannot be equal, cannot be compared to NULL as far as you had defined it. The check itself looks suspicious, what had you wanted to do?
data_vec.insert(add,new_data);
insert receives an iterator as first parameter. An integer value isn't an iterator. An iterator of add-th element's iterator value is data_vec.begin() + add. It looks like have to check the documentation on std::vector.
You can find shorthanded documentation here: https://en.cppreference.com/w/cpp/container/vector
If you're trying to learn C++ on your own, this may be helpful: https://isocpp.org/faq
Hoping for some clarification here. The code below executes fine, but when I uncomment that else statement a compilation error occurs. It's because in main I'm specifying a type int event though there's the possibility of type string. I've simplified my actual code to what's below to narrow down on the problem, what can I do to make it so that vector data in main can be of whatever type getNextLineOfData returns?
#include <vector>
using namespace std;
template< typename T>
std::vector<T> getNextLineOfData(bool someBoolean)
{
std::vector<T> data;
if (someBoolean)
{
data.push_back(1);
data.push_back(2);
data.push_back(3);
}
/*
else
{
data.push_back("1");
data.push_back("2");
data.push_back("3");
}
*/
return data;
};
int main()
{
vector<int> data = getNextLineOfData<int>(true);
return 0;
}
You are confusing compile time operations with runtime operations in your code snippet. When you template the function getNextLineOfData and instantiate it with getNextLineOfData<int>, the compiler goes ahead and generates a function that returns a vector for you. The if statement however is only evaluated at run time. So when the compiler tries to build your code it sees that you are adding both 1 and "1" to your vector<int> container based on the conditional. This is not allowed.
You could solve your problem with template specialization.
#include <vector>
using namespace std;
template<typename T>
std::vector<T> getNextLineOfData() {
// default
}
template<>
std::vector<int> getNextLineOfData()
{
std::vector<int> data;
data.push_back(1);
data.push_back(2);
data.push_back(3);
return data;
};
template<>
std::vector<std::string> getNextLineOfData()
{
std::vector<std::string> data;
data.push_back("1");
data.push_back("2");
data.push_back("3");
return data;
};
int main()
{
vector<int> data = getNextLineOfData<int>();
return 0;
}
EDIT: As #BobTFish points out, it might be better to overload the function rather than template specialize it. The solution above solves the problem the way you had it initially set up.
Reading from extra information in comments, I would suggest something like:
void getNextLine(std::vector<std::string>& output)
{
output.push_back("string data as you please");
}
void getNextLine(std::vector<int>& output)
{
output.push_back(1);
}
bool nextLineIsIntData()
{
// somehow determine if the coming data is strings or ints
return false;
}
int main()
{
std::vector<std::string> stringData;
std::vector<int> intData;
if (nextLineIsIntData())
getNextLine(intData);
else
getNextLine(stringData);
// do whatever you want
}
Well what you are doing is simply illegal. When you look at the if-else statement you say, well if some condition is true than this will execute but this won't, so it stands too reason that the compiler will ignore the part that is not executed. This is flat out wrong. What you need to do, which is layed out in previous answers is too overload or specialize the function for the different data types.
I should also mention that what you are trying to do is bad style. You are essentially relying on the user too pass the correct bool value, which influences the types you push_back() into the vector. Why do this when you have the power of template pattern matching at your disposal which completely removes the need to rely on correct user input.
In this case and any similar ones you come across it's much better to let the compiler decide
With the code below, the question is:
If you use the "returnIntVector()" function, is the vector copied from the local to the "outer" (global) scope? In other words is it a more time and memory consuming variation compared to the "getIntVector()"-function? (However providing the same functionality.)
#include <iostream>
#include <vector>
using namespace std;
vector<int> returnIntVector()
{
vector<int> vecInts(10);
for(unsigned int ui = 0; ui < vecInts.size(); ui++)
vecInts[ui] = ui;
return vecInts;
}
void getIntVector(vector<int> &vecInts)
{
for(unsigned int ui = 0; ui < vecInts.size(); ui++)
vecInts[ui] = ui;
}
int main()
{
vector<int> vecInts = returnIntVector();
for(unsigned int ui = 0; ui < vecInts.size(); ui++)
cout << vecInts[ui] << endl;
cout << endl;
vector<int> vecInts2(10);
getIntVector(vecInts2);
for(unsigned int ui = 0; ui < vecInts2.size(); ui++)
cout << vecInts2[ui] << endl;
return 0;
}
In theory, yes it's copied. In reality, no, most modern compilers take advantage of return value optimization.
So you can write code that acts semantically correct. If you want a function that modifies or inspects a value, you take it in by reference. Your code does not do that, it creates a new value not dependent upon anything else, so return by value.
Use the first form: the one which returns vector. And a good compiler will most likely optimize it. The optimization is popularly known as Return value optimization, or RVO in short.
Others have already pointed out that with a decent (not great, merely decent) compiler, the two will normally end up producing identical code, so the two give equivalent performance.
I think it's worth mentioning one or two other points though. First, returning the object does officially copy the object; even if the compiler optimizes the code so that copy never takes place, it still won't (or at least shouldn't) work if the copy ctor for that class isn't accessible. std::vector certainly supports copying, but it's entirely possible to create a class that you'd be able to modify like in getIntVector, but not return like in returnIntVector.
Second, and substantially more importantly, I'd generally advise against using either of these. Instead of passing or returning a (reference to) a vector, you should normally work with an iterator (or two). In this case, you have a couple of perfectly reasonable choices -- you could use either a special iterator, or create a small algorithm. The iterator version would look something like this:
#ifndef GEN_SEQ_INCLUDED_
#define GEN_SEQ_INCLUDED_
#include <iterator>
template <class T>
class sequence : public std::iterator<std::forward_iterator_tag, T>
{
T val;
public:
sequence(T init) : val(init) {}
T operator *() { return val; }
sequence &operator++() { ++val; return *this; }
bool operator!=(sequence const &other) { return val != other.val; }
};
template <class T>
sequence<T> gen_seq(T const &val) {
return sequence<T>(val);
}
#endif
You'd use this something like this:
#include "gen_seq"
std::vector<int> vecInts(gen_seq(0), gen_seq(10));
Although it's open to argument that this (sort of) abuses the concept of iterators a bit, I still find it preferable on practical grounds -- it lets you create an initialized vector instead of creating an empty vector and then filling it later.
The algorithm alternative would look something like this:
template <class T, class OutIt>
class fill_seq_n(OutIt result, T num, T start = 0) {
for (T i = start; i != num-start; ++i) {
*result = i;
++result;
}
}
...and you'd use it something like this:
std::vector<int> vecInts;
fill_seq_n(std::back_inserter(vecInts), 10);
You can also use a function object with std::generate_n, but at least IMO, this generally ends up more trouble than it's worth.
As long as we're talking about things like that, I'd also replace this:
for(unsigned int ui = 0; ui < vecInts2.size(); ui++)
cout << vecInts2[ui] << endl;
...with something like this:
std::copy(vecInts2.begin(), vecInts2.end(),
std::ostream_iterator<int>(std::cout, "\n"));
In C++03 days, getIntVector() is recommended for most cases. In case of returnIntVector(), it might create some unncessary temporaries.
But by using return value optimization and swaptimization, most of them can be avoided. In era of C++11, the latter can be meaningful due to the move semantics.
In theory, the returnIntVector function returns the vector by value, so a copy will be made and it will be more time-consuming than the function which just populates an existing vector. More memory will also be used to store the copy, but only temporarily; since vecInts is locally scoped it will be stack-allocated and will be freed as soon as the returnIntVector returns. However, as others have pointed out, a modern compiler will optimize away these inefficiencies.
returnIntVector is more time consuming because it returns a copy of the vector, unless the vector implementation is realized with a single pointer in which case the performance is the same.
in general you should not rely on the implementation and use getIntVector instead.
I'm trying create a class which adds functionality to a generic class, without directly interfacing with the wrapped class. A good example of this would be a smart pointer. Specifically, I'd like to create a wrapper which caches all the i/o for one (or any?) method invoked through the wrapper. Ideally, the cache wrapper have the following properties:
it would not require the wrapping class to be changed in any way (i.e. generic)
it would not require the wrapped class to be changed in any way (i.e. generic)
it would not change the interface or syntax for using the object significantly
For example, it would be really nice to use it like this:
CacheWrapper<NumberCruncher> crunchy;
...
// do some long and ugly calculation, caching method input/output
result = crunchy->calculate(input);
...
// no calculation, use cached result
result = crunchy->calculate(input);
although something goofy like this would be ok:
result = crunchy.dispatch (&NumberCruncher::calculate, input);
I feel like this should be possible in C++, although possibly with some syntactic gymnastics somewhere along the line.
Any ideas?
I think I have the answer you are seeking, or, at least, I almost do. It uses the dispatch style you suggested was goofy, but I think it meets the first two criteria you set forth, and more or less meets the third.
The wrapping class does not have to be modified at all.
It doesn't modify the wrapped class at all.
It only changes the syntax by introducing a dispatch function.
The basic idea is to create a template class, whose parameter is the class of the object to be wrapped, with a template dispatch method, whose parameters are the argument and return types of a member function. The dispatch method looks up the passed in member function pointer to see if it has been called before. If so, it retrieves the record of previous method arguments and calculated results to return the previously calculated value for the argument given to dispatch, or to calculate it if it is new.
Since what this wrapping class does is also called memoization, I've elected to call the template Memo because that is shorter to type than CacheWrapper and I'm starting to prefer shorter names in my old age.
#include <algorithm>
#include <map>
#include <utility>
#include <vector>
// An anonymous namespace to hold a search predicate definition. Users of
// Memo don't need to know this implementation detail, so I keep it
// anonymous. I use a predicate to search a vector of pairs instead of a
// simple map because a map requires that operator< be defined for its key
// type, and operator< isn't defined for member function pointers, but
// operator== is.
namespace {
template <typename Type1, typename Type2>
class FirstEq {
FirstType value;
public:
typedef std::pair<Type1, Type2> ArgType;
FirstEq(Type1 t) : value(t) {}
bool operator()(const ArgType& rhs) const {
return value == rhs.first;
}
};
};
template <typename T>
class Memo {
// Typedef for a member function of T. The C++ standard allows casting a
// member function of a class with one signature to a type of another
// member function of the class with a possibly different signature. You
// aren't guaranteed to be able to call the member function after
// casting, but you can use the pointer for comparisons, which is all we
// need to do.
typedef void (T::*TMemFun)(void);
typedef std::vector< std::pair<TMemFun, void*> > FuncRecords;
T memoized;
FuncRecords funcCalls;
public:
Memo(T t) : memoized(t) {}
template <typename ReturnType, typename ArgType>
ReturnType dispatch(ReturnType (T::* memFun)(ArgType), ArgType arg) {
typedef std::map<ArgType, ReturnType> Record;
// Look up memFun in the record of previously invoked member
// functions. If this is the first invocation, create a new record.
typename FuncRecords::iterator recIter =
find_if(funcCalls.begin(),
funcCalls.end(),
FirstEq<TMemFun, void*>(
reinterpret_cast<TMemFun>(memFun)));
if (recIter == funcCalls.end()) {
funcCalls.push_back(
std::make_pair(reinterpret_cast<TMemFun>(memFun),
static_cast<void*>(new Record)));
recIter = --funcCalls.end();
}
// Get the record of previous arguments and return values.
// Find the previously calculated value, or calculate it if
// necessary.
Record* rec = static_cast<Record*>(
recIter->second);
typename Record::iterator callIter = rec->lower_bound(arg);
if (callIter == rec->end() || callIter->first != arg) {
callIter = rec->insert(callIter,
std::make_pair(arg,
(memoized.*memFun)(arg)));
}
return callIter->second;
}
};
Here is a simple test showing its use:
#include <iostream>
#include <sstream>
#include "Memo.h"
using namespace std;
struct C {
int three(int x) {
cout << "Called three(" << x << ")" << endl;
return 3;
}
double square(float x) {
cout << "Called square(" << x << ")" << endl;
return x * x;
}
};
int main(void) {
C c;
Memo<C> m(c);
cout << m.dispatch(&C::three, 1) << endl;
cout << m.dispatch(&C::three, 2) << endl;
cout << m.dispatch(&C::three, 1) << endl;
cout << m.dispatch(&C::three, 2) << endl;
cout << m.dispatch(&C::square, 2.3f) << endl;
cout << m.dispatch(&C::square, 2.3f) << endl;
return 0;
}
Which produces the following output on my system (MacOS 10.4.11 using g++ 4.0.1):
Called three(1)
3
Called three(2)
3
3
3
Called square(2.3)
5.29
5.29
NOTES
This only works for methods which take 1 argument and return a result. It doesn't work for methods which take 0 arguments, or 2, or 3, or more arguments. This shouldn't be a big problem, though. You can implement overloaded versions of dispatch which take different numbers of arguments up to some reasonable max. This is what the Boost Tuple library does. They implement tuples of up to 10 elements and assume most programmers don't need more than that.
The possibility of implementing multiple overloads for dispatch is why I used the FirstEq predicate template with the find_if algorithm instead of a simple for loop search. It is a little more code for a single use, but if you are going to do a similar search multiple times, it ends up being less code overall and less chance to get one of the loops subtlely wrong.
It doesn't work for methods returning nothing, i.e. void, but if the method doesn't return anything, then you don't need to cache the result!
It doesn't work for template member functions of the wrapped class because you need to pass an actual member function pointer to dispatch, and an un-instantiated template function doesn't have a pointer (yet). There may be a way around this, but I haven't tried much yet.
I haven't done much testing of this yet, so it may have some subtle (or not-so-subtle) problems.
I don't think a completely seamless solution which satisfies all your requirements with no change in syntax at all is possible in C++. (though I'd love to be proven wrong!) Hopefully this is close enough.
When I researched this answer, I got a lot of help from this very extensive write up on implementing member function delegates in C++. Anyone who wants to learn way more than they realized was possible to know about member function pointers should give that article a good read.
I don't think this can be easily done using just a wrapper as you'll have to intercept the IO calls, so wrapping a class would put the code at the wrong layer. In essence, you want to substitute the IO code underneath the object, but you're trying to do it from the top layer. If you're thinking of the code as an onion, you're trying to modify the outer skin in order to affect something two or three layers in; IMHO that suggests the design might need a rethink.
If the class that you're trying to wrap/modify this way does allow you to pass in the stream (or whatever IO mechanism you use), then substituting that one for a caching one would be the right thing to do; in essence that would be what you'd be trying to achieve with your wrapper as well.
It looks like a simple task, assuming the "NumberCruncher" has a known interface, let's say int operator(int).
Note that you'll need to make it more complicated to support other interfaces. In order to do so, i'm adding another template parameter, an Adaptor. Adaptor should convert some interface to a known interface. Here's simple and dumb implementation with static method, which is one way to do it. Also look what Functor is.
struct Adaptor1 {
static int invoke(Cached1 & c, int input) {
return(c.foo1(input));
}
};
struct Adaptor2 {
static int invoke(Cached2 & c, int input) {
return(c.foo2(input));
}
};
template class CacheWrapper<typename T, typeneame Adaptor>
{
private:
T m_cachedObj;
std::map<int, int> m_cache;
public:
// add c'tor here
int calculate(int input) {
std::map<int, int>::const_iterator it = m_cache.find(input);
if (it != m_cache.end()) {
return(it->second);
}
int res = Adaptor::invoke(m_cachedObj, input);
m_cache[input] = res;
return(res);
}
};
I think what you need is something like a proxy / decorator (design patterns). You can use templates if you don't need the dynamic part of those patterns. The point is that you need to well define the interface that you will need.
I haven't figured out the case for handling object methods, but I think I've got a good fix for regular functions
template <typename input_t, typename output_t>
class CacheWrapper
{
public:
CacheWrapper (boost::function<output_t (input_t)> f)
: _func(f)
{}
output_t operator() (const input_t& in)
{
if (in != input_)
{
input_ = in;
output_ = _func(in);
}
return output_;
}
private:
boost::function<output_t (input_t)> _func;
input_t input_;
output_t output_;
};
Which would be used as follows:
#include <iostream>
#include "CacheWrapper.h"
double squareit(double x)
{
std::cout << "computing" << std::endl;
return x*x;
}
int main (int argc, char** argv)
{
CacheWrapper<double,double> cached_squareit(squareit);
for (int i=0; i<10; i++)
{
std::cout << cached_squareit (10) << std::endl;
}
}
Any tips on how to get this to work for objects?