C++ Using the "this" pointer as a normal pointer - c++

I am currently trying to use the "this" pointer to pass a pointer to a function:
void GameObject::process_events()
{
std::vector<ObjectEvent*>::iterator it;
for (it = events.begin(); it != events.end(); it++)
(*it)->process(this);
}
Class ObjectEvent
{
private:
bool* trigger;
void (*response)(GameObject*);
public:
process(GameObject* obj)
{
if (*trigger)
response(obj);
}
};
But I get an error:
No matching function call to 'ObjectEvent::process(GameObject* const)'
What could be the problem?

Judging by your error message, process_events() appears to actually be a const function.
void GameObject::process_events() const
{
process(this);
}
If so, then this is a const pointer and process() must take a const GameObject *. Otherwise process() could modify the point that gets passed to it, which violates process_events's promise not to modify this.
void process(const GameObject* obj);
Alternatively, remove the const modifier from process_events().

If the member function you're returning this from or using this in is const, then it will be a const pointer. If the member function is not declared const, the pointer won't be either.
void GameObject::process_events()
{
// ...
process(this); // 'this' is NOT a const pointer
}
void GameObject::process_events() const
{
// ...
process(this); // 'this' IS a const pointer
}

Related

why is there a "no instance of overloaded function matches the argument list" error when attempting vector push_back?

I am doing an assignment for a C++ class and I am getting an error when using push back with vector. I honestly cannot find any info on why this isnt working and giving me a "no instance of overloaded function" error
class StudentData {
class StudyModule {
private:
const int studyModuleCode;
const std::string studyModuleName;
public:
StudyModule();
StudyModule(const StudyModule& copy);
~StudyModule();
};
private:
const int studentNumber;
std::string studentName;
std::vector<StudyModule*> modules;
public:
StudentData();
StudentData(const StudentData& copy);
~StudentData();
void addModules(const StudyModule& module);
int howManyModules();
};
void StudentData::addModules(const StudyModule& module)
{
this->modules.push_back(&module);
}
The function addModules() is declared like this:
void addModules(const StudyModule& module);
that is, its parameter is a reference to const object.
But the vector has a pointer to a non-const object as its template argument:
std::vector<StudyModule*> modules;
Thus, the compiler issues a message for this statement:
this->modules.push_back(&module);
because the expression &module has the type const StudyModule *, ie a pointer to a const object.
Even if you would change the template argument of the vector like this:
std::vector<const StudyModule *> modules;
your approach will be unsafe, because the user can pass a temporary object of type StudyModule to the function. In this case, storing a pointer to this object in the vector will become invalid when the temporary object is destroyed afterwards.

How can I pass a member function pointer into a function that takes a regular function pointer?

I have a player class which looks like this (stripped down to what is needed for this problem):
class Player
{
public:
Player();
~Player();
void kill();
void death();
void reset();
};
The kill(), death(), and reset() functions look like this:
void Player::kill()
{
void (*dPtr)() = &death;
Game::idle(dPtr, 48);
}
void Player::death()
{
reset();
}
void Player::reset()
{
//resets
}
The idle function is a static memeber function of Game, which takes a function pointer and an integer n, and calls the function after n tick. Here is the function, the implementation shouldn't matter:
class Game {
static void idle(void (*)(), int);
};
This code gives me the error:
ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say '&Player::death' [-fpermissive]
So I change the line from
void (*dPtr)() = &death;
to
void (Player::*dPtr)() = &Player::death;
to solve that issue. But then my call to the idle function is incorrect, as it takes a regular function pointer, and I am passing in a member function pointer, and thus gives me the error:
no matching function for call to 'Game::idle(void (Player::*&)(), int)'
So my question is:
How can I pass the member function pointer Player::*dPtr into the idle function, which takes a void (*)() as an argument?
Or is there another way I can solve my previous error which forbids me from taking the address of an unqualified member function to form a pointer to a member function?
Another answer mentions that you need two pointers. However C++ already comes with containers for doing just this, so it would make your code a lot simpler to use those. (In C++03, some of the std:: items below were std::tr1::).
Sample code:
#include <iostream>
#include <functional>
struct Game
{
static void idle( std::function<void()> func, int x )
{ std::cout << "x = " << x << "\n"; func(); }
};
struct Player
{
void death() { std::cout << "player.death\n"; }
void kill() { Game::idle( std::bind(&Player::death, this), 48 ); }
};
int main()
{
Player p;
p.kill();
}
Lifetime note: std::bind binds by value. Using *this means a copy of the Player is made and stored in the std::function object, copied around with it as necessary.
Using this means the function object stores a pointer, so if you actually store the function object in Game::idle you must take care that this Player is not destroyed before removing this function object from Game::idle's list.
To call a member function through a pointer, you need two pointers: the pointer to the function itself, and a pointer to an object to be this. Your Game::idle API does not support this usage. You need to change it so that it passes at least one argument (conventionally of type void *) to the callback. Then you can use the following pattern:
struct Player
{
// ...
void kill();
// ...
static void call_kill(void *self);
};
void Player::call_kill(void *self)
{
static_cast<Player *>(self)->kill();
}
struct Game
{
static void idle(void (*)(void *), void *, int);
};
void Game::idle(void (*callback)(void *), void *arg, int ticks)
{
// ...
callback(arg);
// ...
}
void kill_player_delayed(Player *p, int ticks)
{
Game::idle(Player::call_kill, static_cast<void *>(p), ticks);
}
You have to write a static call_X method for every instance method X you want to call.
An alternative approach, which is arguably more C++-idiomatic and flexible, and involves less explicitly written-out code, but has higher runtime costs (three indirect function calls and a heap allocate-free cycle per invocation, instead of a single indirect function call), is to have Game::idle take an object of a particular class, with a virtual callback method. That class is then given a template subclass that can call anything that implements operator(), such as the result of std::bind.
struct Runnable { virtual ~Runnable(); virtual void invoke() = 0; };
template <typename T> struct TRunnable : Runnable {
TRunnable(T target) : target(target) {}
void invoke() { target(); }
private:
T target;
};
template <typename T> TRunnable<T>* make_Runnable(T obj)
{ return new TRunnable<T>(obj); }
struct Game
{
static void idle(Runnable *, int);
};
void Game::idle(Runnable *r, int ticks)
{
// ...
r->invoke();
delete r;
// ...
}
struct Player
{
// ...
void kill();
// ...
};
void kill_player_delayed(Player *p, int ticks)
{
Game::idle(make_Runnable(std::bind(&Player::kill, p)), ticks);
}
You cannot make Game::idle take the result of std::bind directly because that object's type is unspecified (and varies depending on how you call std::bind), so it can only be used as an argument to a template function call. A virtual method call to an adapter class is the only way to keep Game::idle compiled out-of-line and still let it use bound-call objects.
In either approach, beware object lifetime issues. In particular, if Game::idle does not call its callback before returning, you need to
make sure that both the original object, and (in the second approach)
the object returned by make_Runnable survive until the callback fires. This is why make_Runnable uses new.
Because I really don't like the answer that casts void*'s to other objects (almost never necessary in C++!) and nobody has posted an answer using the suggestions in the comments I'm going to suggest this.
Use a templated type for your callback!
Like this:
class Game{
template<typename Func>
static void idle(Func &&func, int i){
// game stuff
func();
// other game stuff
}
};
Then you don't lose all of your type safety (casting void*) and it should be the fastest solution.
Also, where you are assigning a function pointer, you can change the code to be far more readable in this case:
void Player::kill(){
Game::idle([this](){this->death();}, 48);
}
Which is far nicer than having to write the correct function pointer type.
You cannot do that simply because pointer to [static] function is a single pointer sizeof void*. In contrary member function need more information, e.g. two pointers: one for this and another one for the function itself so member function pointer has sizeof > sizeof(void*).
Therefore you have two options:
to change signature of your idle() to this void idle(void (*)(), void*, int); so you will be able to pass this somehow.
Or make static variable that will hold this pointer. But that assumes that only one death() can be at idle queue at any given moment of time.
1) is what people do usually in such cases.

passing STL container in a class to another class

I am trying to pass a STL container in a class to another class
For ex.
typedef std::map<std::string, int*> Container_t;
class A
{
public:
const Container_t * get_container() const;
private:
Container_t container;
};
const Container_t * A::get_container() const
{
return &container;
}
And when I try to get this in another class, I get compilation error
saying
error: argument of type ‘Container_t* (A::)()const’ does not match ‘Container_t*’
void foo(A * a)
{
const Container_t * container = a->get_container();
}
It will be best if I can get const reference instead of pointer. but I don't want to copy the return value of function in A. So it has to be either pointer or reference. Thank you
You need to change your function signature to:
const Container_t * get_container() const;
The reason is that the last const there at the end says "calling this function and using what it returns will not change this object." However, returning a (non-const) pointer to the member variable gives the caller freedom to change that variable, so you have to return a const Container_t * to ensure that the caller doesn't modify the member variable (and thereby modify the object).

const correctness with smart pointers

I'm trying to understand better how does const-correctness work and more specifically, when dealing with classes whose members are based on containers and smart pointers.
I guess that the const-correctness property is the same regardless of the class members. However, since I'm having some difficulties to clearly understand what's going on,
I decided to ask you for advice.
So, here is the context. I've a ShapeContainer class that has as private class member a vector of smart pointers.
The Shape class is abstract and has the following virtual function virtual float doSomething(); which is then redefined by its derived classes. Note that it's a non-const class function.
The relevant part of the code is given below:
class ShapeContainer{
public:
typedef std::shared_ptr<Shape> ShapePtr;
typedef std::vector<ShapePtr> ShapePtrContainer;
// .......
const ShapePtr & operator[]( int ) const { return m_vect[index]; }; // const version
// ShapePtr & operator[]( int ) { return m_vect[index]; }; // non-const version
// .......
private:
ShapePtrContainer m_vect;
};
class Shape{
public:
// ...
virtual float doSomething() = 0;
};
Here are my questions.
Q1. Why do I'm allowed to call the doSomething() function in the following way: int index = 0; float tmp = container1[index]->doSomething(); (having ShapeContainer container1=createBasicShapes();)?
From what I understand, after calling to the const ShapePtr operator[] const function we'll get a const pointer to a Shape object, however the doSomething() virtual
function is not const. So, how does a reference to a const-object can call a non-const function?
Q2. By calling the doSomething() function as previouly ilustrated (float tmp =container1[index]->doSomething();) and by adding a non-const version of the operator[], this latter
overloaded version is then called instead of the const-version one. Why does it is so?
Now, instead of having a ShapeContainer class, I've now a new class named ShapeContainerInfo that still has a vector but of an intermediate ShapeInfo class (that has a smart pointer as a class member).
class ShapeContainerInfo{
public:
typedef std::vector<ShapeInfo> ShapeContainer;
const ShapeInfo & operator []( int index) const { return m_vect[index]; };
// ShapeInfo & operator []( int index) { return m_vect[index]; }; // non-const version
private:
ShapeContainer m_vect;
};
class ShapeInfo{
public:
typedef std::shared_ptr<Shape> ShapePtr;
// ...
float doSomething(){ return m_ShapePtr->doSomething(); };
private:
ShapePtr m_ShapePtr;
int m_nID;
};
Q3. When I call float tmp = container2[i].doSomething();, I get the following compiler error: error C2662: 'ShapeInfo::doSomething' : cannot convert 'this' pointer from 'const ShapeInfo' to 'ShapeInfo &'.
However, when I add a non-const vesion of the overloaded operator [] the compiler error is gone. So, why do I really need the non-const operator[] for ShapeContainerInfo and not for ShapeContainer?
Q4. If the m_vect private member of ShapeContainerInfo is set now as public member and only the const-version of operator[] is defined (not the non-const one), there are no compiler error messages. Why this? e.g. after setting m_vect to be a public class member: float tmp = info.m_vect[i].doSomething();
Q5. How could I correctly define both the ShapeInfo and ShapeContainerInfo classes such that I only need to define the const-version of the operator[] and still being able to call the float doSomething() function?
For those of you interested in the whole sample code, please find it here.
Clarifications, suggestions are always welcomed :-)
Merci!
Q1: The shared_ptr is const, that doesn't mean that the pointed to object is const. For that you would want shared_ptr<const Shape>.
Q2: Since you're ShapeContainer was not const, the non-const function was a better match, so it was called instead of the const version.
Q3: vector propagates its constness to its elements. shared_ptr does not. This is inline with the behavior of arrays and raw pointers. The elements of const arrays are const. The thing pointed to by a const pointer is not (necessarily) const.
Q4: Are you saying this produces no error?
ShapeContainerInfo info;
info[0].doSomething();
Please clarify, because that should be an error.
Q4: Okay, so you're saying that this produces no error:
ShapeContainerInfo info;
info.m_vect[0].doSomething();
Nor should it. The vector is not const. It's only inside the const member function that the vector(and all other members) are treated as const.
Q5: Make m_vect a vector of unique pointers. Inside the const function, the vector itself will be const, and the unique pointers will be const. But the objects that the unique pointers point to will be mutable.
As an example, the set function in this class is not legal:
struct Foo
{
void set(int index, int value) const
{
v[index] = value;
}
std::vector<int> v;
};
But this one is:
struct Foo
{
void set(int index, int value) const
{
*v[index] = value;
}
std::vector<std::unique_ptr<int>> v;
};

Casting const void* to const int*

I haven't used void* and const_correctness before so I am not understanding what I am doing wrong in the below code. All I want is to cast a void* returned by a member function of a const object to int*. Please suggest better approaches. Thank you.
I get the following error
passing 'const MyClass' as 'this' argument of 'void* MyClass::getArr()' discards qualifiers
So here's the actual program that I had problem with
class MyClassImpl{
CvMat* arr;
public:
MyClassImpl(){arr = new CvMat[10];}
CvMat *getArr(){return arr;}
};
class MyClass{
MyClassImpl *d;
public:
const void *getArr()const{ return (void*)d->getArr(); }
};
void print(const MyClass& obj){
const int* ptr = static_cast<const int *>(obj.getArr());
}
int main(){
MyClass obj1;
print(obj1);
}
Only the methods such as 'print()' in this case know the datatype returned by 'getData'. I can't use templates because the user doesn't know how MyClass is implemented. Thank you. Feel free to suggest alternatives.
I think the problem is not in the cast from your array to a void * but in trying to call obj.getArr() when obj is marked const and MyClass::getArr() is not a const member function. If you change your definition of that member function to
const void *getArr() const { return static_cast<const void*>(arr); }
Then this error should resolve itself. You might want to do a const-overload as well:
const void *getArr() const { return static_cast<const void*>(arr); }
void *getArr() { return static_cast< void*>(arr); }