I know Class *cls is a pointer, and Class &cls takes the address, but what is
void fucction1( Class *&cls)
If I have Class c, what should I pass to function1()?
Thanks!
Besides, what James explained in his response, let me add one more important point to it.
While you can write Class* & (reference to pointer) which is perfectly valid in C++ only, you cannot write Class& * (pointer to reference), as you cannot have a pointer to a reference to any type. In C++, pointer to reference is illegal.
ยง8.3.2/4 from the language specification reads,
There shall be no references to
references, no arrays of references,
and no pointers to references.
If I have Class c, what should I pass
to function1()?
You can write your calling code like this:
Class *ptrClass;
//your code; may be you want to initialize ptrClass;
function1(ptrClass);
//if you change the value of the pointer (i.e ptrClass) in function1(),
//that value will be reflected here!
//your code
For a type T, T* is a pointer to an object of type T, so Class* is a pointer to a Class object.
For a type T, T& is a reference to an object of type T, so putting them together, Class*& is a reference to a pointer to a Class object.
Class c;
Class* c_ptr = &c;
function1(c_ptr);
Would work. But note that rvalue-references is only possible with C++0x which most compilers haven't fully implemented them. Thus the following wouldn't work:
Class c;
function1(&c);
As said, a reference to a pointer to Class.
you pass a Class * to the function
the function may change the pointer to a different one
This is a rather uncommon interface, you need more details to know what pointers are expected, and what you have to do with them.
Two examples:
Iteration
bool GetNext(Classs *& class)
{
if (class == 0)
{
class = someList.GetFirstObject();
return true;
}
class = somePool.GetObjectAbove(class); // get next
return class != 0;
}
// Use for oterating through items:
Class * value = 0;
while (GetNext(value))
Handle(value);
Something completely different
void function (Class *& obj)
{
if (IsFullMoon())
{
delete obj;
obj = new Class(GetMoonPos());
}
}
In that case, the pointer you pass must be new-allocated, and the pointer you receive you need to pass either to function again, or be delete'd by you.
Related
I am trying to write a class that will be appended with some function pointers.
This pointers will be called from another method of this class. I will be storing the function pointers on a void* vector so anything can go on a single vector, instead of a different vector for each type.
I intend to declare a different AppendCallback methods for any different function I need to call from inside the class, for example:
void MyClass:AppendCallback(void (*Callback)())
{
_CallbackVector.push_back((void*)Callback);
_IdVector.push_back(VoidID);
}
void MyClass:AppendCallback(void (*Callback)(uint32_t));
void MyClass:AppendCallback(void (*MyOtherClass::Callback)());
void MyClass:AppendCallback(void (*MyOtherClass::Callback)(uint32_t));
There will be a second vector that only contains identifiers to know what the void* points to, this is going to be assigned also on the AppendCallback Methods.
How can I cast the void pointer again to the function pointers for calling those functions?
Maybe something like this?
void MyClass::Service(uint32_t x)
{
for(uint i = 0; i < _CallbackVector.size(); i++)
{
switch(_IdVector[i])
{
case VoidID: void(*_CallbackVector[i]()); break;
case Uint32ID: void(*_CallbackVector[i](x)); break;
}
}
}
Edit:
Is this a proper way of casting from a void* to a function pointer?
That's not allowed in C++:
Converting a void* to a function pointer directly is not allowed (should not compile using any of the casts) in C++98/03. It is conditionally supported in C++0x (an implementation may choose to define the behavior and if it does define it then it must do what the standard says it should do. A void*, as defined by the C++98/03 standard, was meant to point to objects and not to contain function pointers or member pointers.
And again:
You can't.
You can cast a data pointer to void* and then back to the same pointer type you have started with. std::function is not a pointer type, so the cast is statically invalid, and it's not the same thing you have started with. You have started with a .target of type void()() but it's not a data pointer, it's a function pointer, so casting it to void and back is implementation-defined.
In your specific situation, you could try something like this:
class PointerToFunction {
};
template <typename Type>
class PointerToFunctionType : public PointerToFunction, std::function<Type> {
public:
using std::function<Type>::function; // I think this is the right syntax for this trick: https://softwareengineering.stackexchange.com/a/197901/342247
};
// Now, we can do this:
std::vector<PointerToType*> _CallbackVector;
Basically, we're using an inheritance trick similar to how boost::any/std::any (since C++17) is implemented to store any std::function in a pointer. The only issue is knowing how to convert it back. Doing this properly would depend on how you expected to convert that void* back to begin with (i.e., knowing its type), so I'll leave that part up to you.
I'm trying to keep a reference to a pointer of a different class in my class. I'm trying to see if there is a way to do this without having to define it in the ctor. I cannot make a copy, as I'm using that specific pointer returned to do other things.
class MyClass {
private:
OtherClassPtr &m_ptr_ref;
public:
MyClass();
public:
void MyFunction() {
m_ptr_ref = otherClassPtr->GetPtrRef();
if(!m_ptr_ref)
return;
}
};
A reference needs to be initialized at the point of declaration, and cannot change to refer to a different object during its lifetime. Thus you need to set it in the constructor.
An alternative is to store a pointer. I think of a reference as a pointer with nicer syntax, though the different syntax gives it a different semantic meaning; it acts like the object that it refers to, and so has the same value and the same address as that object. Most relevant to your question, the assignment operator works like assignment to the object, rather than a pointer. This is the reason it cannot change referent.
You can keep a pointer to the pointer:
OtherClassPtr* m_ptr_ref;
/* ... */
m_ptr_ref = &otherClassPtr->GetPtrRef();
An alternative is to use std::reference_wrapper, but that is nothing more than a fancy pointer, and I don't see the advantage over using a pointer.
I was wandering through the code of Sequitur G2P and found a really strange line of code:
public:
...
const Node *childrenEnd() const { return (this+1)->finalized.firstChild_; }
I know that this is a pointer to the current object, and since it is a pointer, the operation is perfectly legal, but what does this+1 actually refer to?
Presumably this is part of an array, so this+1 would refer to the next object in that array.
this is simply a pointer which refers to this object. Since it's a pointer, you can apply pointer arithmetic and even array indexing.
If this object is an element in an array, this+1 would point to the next object in the array.
If it's not, well it's just going to treat whatever is at that memory the same as this object, which will be undefined behaviour unless it is the same type.
As it is NLP it makes sense to optimize memory management. I assume you find overloaded new/delete methods as well.
The this+1 construct assumes all objects reside in an array. The name 'childrenEnd' of the method indicates it returns a pointer to an address of the end of the children of the current node.
Thus you are looking at an implementation of a tree structure. All siblings are adjacent and their children as well.
"this + 1" in C++ class means:
if the "this" object is a member of another object it will point to the address of the parent's object next variable declared just after the "this" object variable:
Example:
class B
{
public:
void* data()
{
return this + 1;
}
};
class A
{
public:
B m_b;
char m_test;
};
int main(int argc, char* argv[])
{
A a;
a.m_test = 'H';
void* p = a.m_b.data();
char c;
memcpy(&c, p, sizeof(char));
return 0;
}
c is equal 'H'.
Long story short it allows to access to parent's class data without passing parent's pointer to the child class. In this example this + 1 point to the m_test member of the class A.
Actually, there is a case, when this thing could be used. I don't recommend to use this method, but it certainly works.
I believe, in NLP code it was used something like that:
when you want your object to behave as a collection (an array etc) to use it similarly as an array with something range-based etc, you can do this trick:
struct Obj {
...
Obj* begin() { return this; }
Obj* end() { return this+1; }
...
}
Now, you can use this object in, for example, range-based for-loops...
Sometimes all that is necessary... but just even there you'd better use "nullptr" or even do refactoring than to use this trick.
I have run into a strange problem. When i try to write a function that returns a pointer to a subclass which i swap for a different instance of that subclass i get the "error C2106: '=' : left operand must be l-value" error.
Tthe problems is at the one->getMe() = two; line :
class subClass{};
class someClass{
public:
subClass * pointer;
someClass(){
pointer = new subClass;
}
subClass * getMe(){
return pointer;
}
};
int main(){
someClass * one = new someClass;
subClass * two = new subClass;
one->getMe() = two;
}
I'm a bit new to c++ so the problem might be horrible simple. Any help is much appreciated.
The pointer that you return from the function is a copy of the pointer in the object. It is a temporary, you cannot assign to it. Even if you could assign to it, it would do no good, because it is no longer connected to the pointer in your object. If you want to be able to assign to the object's pointer after returning it from the function, you want to return the pointer by reference.
subClass *& getMe() {
return pointer;
}
You should also may want to consider adding a const overload in order to work on const objects. It might look like this:
subclass * const & getme() const {
return pointer;
}
The line
one->getMe() = two;
Is trying to assign the pointer at two to one->getMe(). But one->getMe() returns a temporary copy which you cannot assign to. If you want to return the pointer by reference and thus be able to change it then you can use the signature
subClass *& getMe();
as others have suggested.
That being said, you're exposing the inner workings of a class for all and sundry to see and modify, in particular pointers to objects on the heap which may or may not be deallocated correctly which is unwise.
I have some confusion about the shared_ptr copy constructor. Please consider the following 2 lines:
It is a "constant" reference to a shared_ptr object, that is passed to the copy constructor so that another shared_ptr object is initialized.
The copy constructor is supposed to also increment a member data - "reference counter" - which is also shared among all shared_ptr objects, due to the fact that it is a reference/pointer to some integer telling each shared_ptr object how many of them are still alive.
But, if the copy constructor attempts to increment the reference counting member data, does it not "hit" the const-ness of the shared_ptr passed by reference? Or, does the copy constructor internally use the const_cast operator to temporarily remove the const-ness of the argument?
The phenomenon you're experiencing is not special to the shared pointer. Here's a typical primeval example:
struct Foo
{
int * p;
Foo() : p(new int(1)) { }
};
void f(Foo const & x) // <-- const...?!?
{
*x.p = 12; // ...but this is fine!
}
It is true that x.p has type int * const inside f, but it is not an int const * const! In other words, you cannot change x.p, but you can change *x.p.
This is essentially what's going on in the shared pointer copy constructor (where *p takes the role of the reference counter).
Although the other answers are correct, it may not be immediately apparent how they apply. What we have is something like this:
template <class T>
struct shared_ptr_internal {
T *data;
size_t refs;
};
template <class T>
class shared_ptr {
shared_ptr_internal<T> *ptr;
public:
shared_ptr(shared_ptr const &p) {
ptr = p->ptr;
++(ptr->refs);
}
// ...
};
The important point here is that the shared_ptr just contains a pointer to the structure that contains the reference count. The fact that the shared_ptr itself is const doesn't affect the object it points at (what I've called shared_ptr_internal). As such, even when/if the shared_ptr itself is const, manipulating the reference count isn't a problem (and doesn't require a const_cast or mutable either).
I should probably add that in reality, you'd probably structure the code a bit differently than this -- in particular, you'd normally put more (all?) of the code to manipulate the reference count into the shared_ptr_internal (or whatever you decide to call it) itself, instead of messing with those in the parent shared_ptr class.
You'll also typically support weak_ptrs. To do this, you have a second reference count for the number of weak_ptrs that point to the same shared_ptr_internal object. You destroy the final pointee object when the shared_ptr reference count goes to 0, but only destroy the shared_ptr_internal object when both the shared_ptr and weak_ptr reference counts go to 0.
It uses an internal pointer which doesn't inherit the contests of the argument, like:
(*const_ref.member)++;
Is valid.
the pointer is constant, but not the value pointed to.
Wow, what an eye opener this has all been! Thanks to everyone that I have been able to pin down the source of confusion to the fact that I always assumed the following ("a" contains the address of "b") were all equivalent.
int const *a = &b; // option1
const int *a = &b; // option2
int * const a = &b; // option3
But I was wrong! Only the first two options are equivalent. The third is totally different.
With option1 or option2, "a" can point to anything it wants but cannot change the contents of what it points to.
With option3, once decided what "a" points to, it cannot point to anything else. But it is free to change the contents of what it is pointing to. So, it makes sense that shared_ptr uses option3.