Errors with std list - c++

For some reason, I keep getting the following errors in ErrorHandler.h
why size function is missing arguments?
'std::list<_Ty>::size': function call missing argument list; use '&std::list<_Ty>::size' to create a pointer to member
'std::_List_iterator<_Mylist> std::list<_Ty>::erase(std::_List_const_iterator<_Mylist>,std::_List_const_iterator<_Mylist>)' : cannot convert parameter 1 from 'int' to 'std::_List_const_iterator<_Mylist>'
'std::_List_iterator<_Mylist> std::list<_Ty>::erase(std::_List_const_iterator<_Mylist>)' : cannot convert parameter 1 from 'int' to 'std::_List_const_iterator<_Mylist>'
// in errorhandler.h
class ErrorHandler{
std::list<unsigned int> m_ErrorList;
public:
ErrorHandler(){ }
~ErrorHandler(){ }
void ForceShutdown(){ free(&m_ErrorList); }
void Add(int errCode){ m_ErrorList.push_back(errCode); }
unsigned int GetLastError(){ if(m_ErrorList.size!=0)return m_ErrorList.back(); }
void Remove(int pos){ if(m_ErrorList.size!=0)m_ErrorList.erase(pos); }
void RemoveRange(int start,int end){ if(m_ErrorList.size!=0)m_ErrorList.erase(start,end); }
};
// in criticalsection.h
class CriticalSection{
long m_nLockCount;
long m_nThreadId;
typedef CRITICAL_SECTION cs;
cs m_tCS;
public:
CriticalSection(){
::InitializeCriticalSection(&m_tCS);
m_nLockCount = 0;
m_nThreadId = 0;
}
~CriticalSection(){ ::DeleteCriticalSection(&m_tCS); }
void Enter(){ ::EnterCriticalSection(&m_tCS); }
void Leave(){ ::LeaveCriticalSection(&m_tCS); }
void Try();
};
class LockSection{
CriticalSection* m_pCS;
ErrorHandler * m_pErrorHandler;
public:
LockSection(CriticalSection* pCS,ErrorHandler* pErrorHandler){
m_pCS = pCS;
m_pErrorHandler = pErrorHandler;
if(!m_pCS)m_pErrorHandler->Add(0x1AE1); // 0x1AE is code prefix for critical section header
if(m_pCS)m_pCS->Enter();
}
~LockSection(){
if(!m_pCS)m_pErrorHandler->Add(0x1AE2);
if(m_pCS)m_pCS->Leave();
}
};

http://www.cplusplus.com/reference/stl/list/pop_back/
Nope, pop_back does not return the last element. This is to prevent accidental errors. You have to get the last element explicitly via back(). This way is also faster if you want to pop several without reading them. This also applies to all the other Standard C++ Library containers.
Judging by your warnings, it looks like you're also having trouble deleting. For Lists it can be tricky:
void Remove(int pos){
std::list<unsigned int>::const_iterator iter = m_ErrorList.begin();
//no need to check the size, advance will throw an exception if pos is invalid
std::advance(iter, pos);
m_ErrorList.erase(iter);
}

You use the list methods badly:
if(m_ErrorList.size!=0)
size is a method, so you need to call it (with parentheses):
if(m_ErrorList.size()!=0)
Note that size is slow for list; you may want to implement GetLastError like this:
unsigned int GetLastError(){ if(!m_ErrorList.empty())return m_ErrorList.back(); }
m_ErrorList.erase(pos);
erase takes an iterator, not an integer. Therefore, you'd better use
std::list::iterator it=m_ErrorList.begin();
std::advance(it, pos);
m_ErrorList.erase(it);
note that this isn't a particularly efficient way, either.
BTW, check that you need list; a vector might serve you better.

Related

Illegal operand error on a function pointer iterator

I am getting the following errors:
'<': illegal, left operand has type 'const_Ty'
'>: illegal, right operand has type 'const_Ty'
in the below code.
It's a relative simple iterator on a function pointer map where the functions are of the form void (Game::*)(UINT). I check the value against a float, then run the function.
The problem seems to be in the for line, although I've got another substantially similar for loop somewhere else that works without a problem.
using FuncPtr = void (Game::*)(UINT);
std::map<FuncPtr, float> funcDelayedTriggerMap;
void Game::PollProcessDelayedTriggers()
{
for (std::map<FuncPtr, float>::iterator it = funcDelayedTriggerMap.begin(); it != funcDelayedTriggerMap.end(); ++it)
{
float currentS = m_timer.GetElapsedSeconds();
if (it->second < currentS)
{
(this->*(it->first))(UINT_MAX);
funcDelayedTriggerMap.erase(it->first);
}
}
}
Member function pointers don't implement operator<, which is the default sorting function std::map uses.
Member function pointers only implement operator== and operator!= .
An easy way to fix this woud be to have a separate key and put the function pointer into the value of the map, e.g.:
std::map<int, std::pair<FuncPtr, float>>
or if you don't need the fast lookup of std::map, a simple vector would also work:
std::vector<std::pair<FuncPtr, float>>
An alternative approach would be to use the function pointer type as key:
using FuncPtr = void (Game::*)(int);
// Just a helper to get a unique type for each function pointer
template<FuncPtr ptr>
struct Tag {};
struct DelayedTrigger {
FuncPtr ptr;
float value;
DelayedTrigger() : ptr(nullptr), value(0.0f) {}
DelayedTrigger(FuncPtr _ptr, float _value) : ptr(_ptr), value(_value) {}
};
std::map<std::type_index, DelayedTrigger> funcDelayedTriggerMap;
void Game::PollProcessDelayedTriggers()
{
for (std::map<std::type_index, DelayedTrigger>::iterator it = funcDelayedTriggerMap.begin(); it != funcDelayedTriggerMap.end(); ++it)
{
float currentS = 1.0;
if (it->second.value < currentS)
{
(this->*(it->second.ptr))(0);
funcDelayedTriggerMap.erase(it->first);
}
}
}
This essentially uses the specific function pointer as a unique key.
You could then add new entries like this:
funcDelayedTriggerMap.emplace(typeid(Tag<&Game::DoIt>), DelayedTrigger{&Game::DoIt, 1.0f});
// or
funcDelayedTriggerMap[typeid(Tag<&Game::DoIt>)] = {&Game::DoIt, 1.0f};
And check if a function is present:
if(funcDelayedTriggerMap.contains(typeid(Tag<&Game::DoIt>))) {
// ...
}
This however only works if you know all the functions you want to use with the map at compile time.

std::vector erase() not working as intended

I'm trying to erase specific elements from a vector of OrderPair while iterating, but it doesn't work as I expect it to. I'm trying to delete every OrderPair with id (first) that equals customer_Id. I do the following:
for(std::vector<OrderPair>::iterator i = source_Orders.begin(); i != source_Orders.end();)
{
if((*i).first == customer_Id)
{
dest_Orders.push_back(*i);
i = source_Orders.erase(i);
}
else
{
i++;
}
}
// definition of OrderPair
typedef std::pair<int, Dish> OrderPair;
// definition of OrderPair
enum DishType{
VEG, SPC, BVG, ALC
};
// definition of OrderPair
class Dish{
private:
const int id;
const std::string name;
const int price;
const DishType type;
};
When the iterator is pointing at an element that fits the if condition, (I can see when debugging that it points to the correct element), the command dest_Orders.push_back(*i); is working as intended, then I'm trying to erase the element which I moved to dest_Orders, and keep going with the next iteration. However, the result is a removal of the last element in the vector source_Orders.
What am I doing wrong here?
Thanks in advance.
There's something you are not showing us.
class Dish{
private:
const int id;
const std::string name;
const int price;
const DishType type;
};
I'm guessing that you originally got an error saying that you can't assign Dish because the members are const. So you added an assignment operator that does nothing. Yay, it now compiles.
Unfortunately, vector depends on the assignment operator actually doing what it says on the tin, because it uses assignment to move the elements around when you erase something in the middle.

Custom iterator out of bounds

I have an iterator class. Let's call it PIterator here. A MessageBuffer is iterated and is being outputted correctly, unless the nSizeOfMessage plus where the iterator currently points to is equal to the size of the whole message (position correct, index one too large).
If I check for the last element and decrement by one, it should work. Though it seems to be a "wrong way" to me. Yeah, I am not quite sure on this, so my problem is shown in this code snippet, maybe someone knows a good solution, tried to figure it out for quite a while.
Yes, I do know how to use a debugger, I know where the problem lies and it is explained just fine. I do not know how to fix this, unless used the way I mentioned.
This compiles fine under Visual Studio 2015.
Please also see the comments in the main function.
#include <iostream>
#include <vector>
class MessageBuffer
{
public:
MessageBuffer(const std::string &s)
{
_msgBuffer.assign(s.begin(), s.end());
}
char &operator[](std::size_t nIndex)
{
return _msgBuffer[nIndex];
}
//more functions...
private:
std::vector<char> _msgBuffer;
};
class PIterator
{
public:
PIterator(MessageBuffer &b)
: m_Ref(b)
, m_Where(0)
{ }
PIterator &operator=(PIterator &other)
{
if (this == &other)
return *this;
this->m_Ref = other.m_Ref;
this->m_Where = other.m_Where;
return *this;
}
//more functions...
PIterator operator+(unsigned int nValue) const
{
PIterator copy(*this);
copy.m_Where += nValue;
return copy;
}
PIterator &operator+=(unsigned int nValue)
{
m_Where += nValue;
return *this;
}
char &operator*()
{
return m_Ref[m_Where];
}
private:
MessageBuffer &m_Ref;
std::size_t m_Where;
};
int wmain(int argv, wchar_t **args)
{
std::string msg = "123MyMessage"; //Length 12
// ^ Index 3, Position 4
MessageBuffer mb(msg);
PIterator itr(mb);
//Calculations - here the results hardcoded
std::size_t nSizeOfMessage = 9; //The size of the message without the numbers
//itr.m_Where is 3 - That's where the non-numeric part of the message starts
itr += 3;
std::string needThis;
PIterator cpy = itr + nSizeOfMessage; //itr points to the first element of the message
//cpy is now out of bounds - position is correct, but index is 1 too large
needThis.assign(&*itr, &*cpy); //boom
return 0;
}
Instead of
needThis.assign(&*itr, &*cpy);
you need to use
needThis.assign(itr, cpy);
This will work if your PIterator satisfies iterator requirements.
The way you call assign, you pass pointers instead of iterators, which is valid by itself. But, to get the pointers, you dereference the iterators first. Dereferencing past-the-end iterator is undefined behavior, which is caught in Debug configuration of the compiler.
The solution I came up with was quite simple.
Instead of having a temporary iterator, I'll be using the char pointer and increment it's address by the size of the message, thus receiving always the correct last element. Should've seen that earlier.
needThis.assign(&*itr, (&*itr) + nSizeOfMessage);

std::deque - subscript out of range

I am writing a plugin for SA-MP, based on AMX and have occured an annoying problem. I am using a deque and a function to find & delete an element. (like this one below)
enum PARAM_TYPE {
PARAM_TYPE_CELL,
PARAM_TYPE_ARRAY,
PARAM_TYPE_STRING,
};
struct params_s {
enum PARAM_TYPE type;
struct params_s * next;
cell free;
cell numData;
cell arrayData[0];
};
struct timer_s {
AMX * amx;
int id, func, interval, repeat;
long long unsigned int trigger;
struct params_s * params;
};
std::deque<struct timer_s *> gTimers;
void DestroyTimer(struct timer_s * t) {
for (int i = 0; i != gTimers.size(); ++i) {
if (t == gTimers[i]) {
gTimers.erase(gTimers.begin() + i);
break;
}
}
}
Whenever I call DestroyTimer() I get this error:
Debug Assertion Failed!
Expression: deque subscript out of range
I can add elements, read and modify them, but I can't delete them.
Thank you.
You should use the erase remove idiom:
void DestroyTimer(struct timer_s * t)
{
gTimers.erase(remove(gTimers.begin(), gTimers.end(), t), gTimers.end());
}
Without looking at the actual error, the idiomatic way would be:
gTimers.erase(std::remove(gTimers.begin(), gTimers.end(), t),
gTimers.end());
This will be safer and faster than what you are doing now (catches
duplicates, no need to reallocate).
This is called Erase-Remove idiom.
For the actual debug assertion: Debugging iterators are a standard
extension and maybe broken in some cases.
NB: You want to call delete on the timer, if it is owned by the deque, to prevent leaking memory.

How to pass a multimap into function

I have a pretty simple question. Im just learning Maps and multimaps and want to know how to pass them into a function. Ive got most of my mind wrapped around multimaps but would like a quick example on how to pass them into a void function.
int main()
{
multimap<string,int> movies;
movies.insert(pair<string,int>("Happy Feet",6));
movies.insert(pair<string,int>("Happy Feet",4));
movies.insert(pair<string,int>("Pirates of the Caribbean",5));
movies.insert(pair<string,int>("Happy Feet",3));
movies.insert(pair<string,int>("Pirates of the Caribbean",4));
movies.insert(pair<string,int>("Happy Feet",4));
movies.insert(pair<string,int>("Flags of out Fathers",4));
movies.insert(pair<string,int>("Gigli",4));
cout<<"There are "<<movies.count("Happy Feet")<<" instances of "<<"Happy Feet"<<endl;
cout<<"There are "<<movies.count("Pirates of the Caribbean")<<" instances of "<<"Pirates of the Caribbean"<<endl;
cout<<"There are "<<movies.count("Flags of out Fathers")<<" instances of "<<"Flags of out Fathers"<<endl;
cout<<"There are "<<movies.count("Gigli")<<" instances of "<<"Gigli"<<endl;
system("PAUSE");
calculateAverage(movies); // this is where im getting errors such as no conversions
return 1;
}
void calculateAverage(multimap<string,int> *q)
{
// this function wont calculate the average obviously. I just wanted to test it
int averageH;
int averageP;
int averageF;
int averageG;
averageH = (q->count("Happy Feet"));
averageP = (q->count("Happy Feet"));
averageF = (q->count("Happy Feet"));
averageG = (q->count("Happy Feet"));
};
Why pass by pointer? I think it is better to pass a reference (if the map shall be modified within the function) or reference to const otherwise
void calculateAverage(const multimap<string,int> & q)
{
// this function wont calculate the average obviously. I just wanted to test it
int averageH;
int averageP;
int averageF;
int averageG;
averageH = (q.count("Happy Feet"));
averageP = (q.count("Happy Feet"));
averageF = (q.count("Happy Feet"));
averageG = (q.count("Happy Feet"));
};
Pass by reference:
void calculateAverage(const multimap<string,int> & q)
But then passing pointer is not that bad. It's just that syntax doesn't look good.
If you choose to pass pointer, then at the calling site, you've to use this syntax:
calculateAverage(&movies);
It seems to me more "in the spirit of the STL" to pass to iterators, movies.begin() and movies.end() to the calculateAverage function. For example:
calculateAverage(movies.begin(),movies.end());
with the following defined:
typedef multimap<string,int>::const_iterator MapIt;
void calculateAverage(const MapIt &begin, const MapIt &end)
{
...
}
You are trying to pass a value of type multimap<string,int> as a pointer to that type, i.e. multimap<string,int>*. Either change the function signature to void calculateAverage(const multimap<string,int>& q) and modify its code accordingly (replace -> with .), or call it like this: calculateAverage(&movies).