A question about pointers

I’m still trying to wrap my head around them, but from my understanding when you pass a pointer between classes (just to be clear using the * symbol) your passing a direct reference to that specific variable. So you don’t need to update that variable on its original class than because you’re updating it.

EXAMPLE 1:
For example, let’s say you have two classes. Class A and Class B.

On Class A you have a pointer called pointer defined as such:



int32 Number = 32;
 int32* Pointer = &Number;


Then in Class B you have:



//Some function to access pointer in class A.
*Pointer = *Pointer + 2;


Then would Number in class A equal 32 or 34 and why would that be the case?

EXAMPLE 2:
Would it work if instead of pointing to an address your pointer is pointing to a class? For example, let’s say you have two classes. Class A and Class B.

On Class A you have a pointer called pointer defined as such:


 UInventory * PlayerInventory;
 

 

Then in Class B you set another pointer to the pointer in Class A.


 LocalPlayerInventory = PlayerInventory
LocalPlayerInventory->AddMoney(100);
 
  

Would the variable PlayerInventory in class A is pointing to be the same as the pointer in Class B is pointing too? Or would they be pointing to separate variables and have separate values?

Pointer hold address to instance of something, depends on pointer type. This works for all types(built-in and user-defined)

It would be nice if you try to write more readable posts.

So all pointers always point to the address in memory then? So for the second example when I change the variable the pointer in Class B is pointing to it will affect the same instance in Class A then. As they are both pointing to that same variable.

I did write a more readable post, i’m not sure what caused it to go crazy. I edited it again and I think I fixed it.

Yes, if you have two pointers that point to the same address/variable, then modifying the value in that address will affect all the others.



int MyInt = 42;
int* PointerA = &MyInt;
int* PointerB = &MyInt;

*PointerA += 2;

// *PointerA, *PointerB, and MyInt will now be 44.


http://www.cplusplus.com/doc/tutorial/pointers/

*Pointer *is an address in memory that points to some other address which contains an object stored.
*Reference *is a variable to an object, but they have no address itself;

Pointers need an address to point to (or point to nullptr), so you cannot make a pointer point to a Ref because refs have no address.
And since Refs don’t own an address, they cannot be initialized to “null”, they must always point to some object as soon you create them.

Keeping those basic rules in mind I think will help to avoid common mistakes :slight_smile:

In my opinion, you should focus on using pointers the way you used them in the Example 2. Example 1 looks very much like your typical C++ pointer example, but in practice you really shouldn’t be messing around with object attributes directly. “->AddMoney(100)” is much better than “Money = *Money + 100” (or whatever combinaison of stars does the trick). And even if you do need to alter object attributes, in most cases you should use a reference.

To expand on the example 2 question: yes, two variables can store the same pointer. This is actually a very most common usecase in UE4 as all UObjects in your code actually NEED to be pointers. You won’t even be able to build if you use UPROPERTY on non-pointer UObjects.

There is no risk to copy pointers and end up with them pointing to different objects. One simple reason is that C++ will not allow you to create a new instance of an object “by mistake”. Creating a UObject in UE4 requires you to call one of a few specific functions, and even then you only end up with a reference because the engine takes care of the rest for you.

Technically references are pointers but you work with them using nonpointer syntax. It’s just syntactic sugar introduced in C++ over pointers in C. It’s also easier to work with references than pointers when they are function params since you can do stuff like this:


void doStuff(const FVector& someVector)

FVector someVector(0.f);

doStuff(someVector);
doStuff(FVector(1.0, 2.0, 3.0));

Whereas if you use pointers it becomes a headache.


void doStuff(const FVector * someVector)

doStuff(&someVector);

FVector someVector2(1.0, 2.0, 3.0);  // can't write the vector param inline
doStuff(&someVector2);

It’s also possible at runtime or with weird typcasting at compile time to assign null to a reference. If you avoid dirty hax while coding you’ll very rarely accidentally assign null to a reference.

If something isn’t a pointer or a reference it’s allocated statically on the stack versus dynamically on the heap. In languages like Java or C# you can’t ever do that with an object. C# does let you do stuff with structs last I checked. In pure non UE4 C++ there is no difference between a struct and a class, except struct params are public by default. This is different if working with UE4 C++ when you work with things that extend UObject since UObjects are classes managed by the garbage collection system of C++ and structs are just structs. But you can mix and match pure C++ with UE4 C++ seamlessly, it just won’t integrate with blueprint whatsoever.


void someFunc() {
    FVector staticallyAllocatedVector(1.f, 2.f, 3.f);

    SomeCppClass staticallyAllocatedCppClass(someConstructorParam);

    SomeCppClass * dynamicallyAllocatedCppClass = new SomeCppClass(someConstructorParam);

    AActor * SomeUnrealActor = SpawnActor<AActor>(whatever the spawn actor function call was and its params go here);

    someOtherFunc(staticallyAllocatedVector, &staticallyAllocatedVector, staticallyAllocatedCppClass, dynamicallyAllocatedCppClass, *dynamicallyAllocatedCppClass, SomeUnrealActor);
}

void someOtherFunc(FVector& vectorReference, FVector * vectorPointer, SomeCppClass& classRef, SomeCppClass * classPtr, SomeCppClass classCopy, AActor * someActorPtr)
{
    vectorReference.X = 10.f;   //this modifies X in staticallyAllocatedVector that was passed in from someFunc()

    vectorPointer->Y = 5.f;        //this modifies Y in staticallyAllocatedVector that was passed in from someFunc()

    classRef.x = 10.f;                //this modifies x in staticallyAllocatedCppClass that was passed in from someFunc()

    classPtr->x = 20.f;               //this modifies x in dynamicallyAllocatedCppClassthat was passed in from someFunc()

    classCopy.x = 1.f;                //classCopy is copied completely when passed from someFunc() and this modifies the local param copy as opposed to the original object, avoid making params that are entire classes or structs to avoid full copies, pass them by const reference instead so it points to the original object e.g. const SomeCppClass& constClassRef so it's immutable

    someActorPtr->SetActorTransform(FTransform(FRotator(1.f, 2.f, 10.f), FVector(1.f));  //sets transform on SomeUnrealActor passed in from someFunc
}

This is a very good point that I forgot to mention in my previous answer:

This only concerns UE4 C++, and only UObjects. It’s true that with structs (or regular objects but don’t do that) you can actually very easily create a clone of your struct with a simple = operator. (Though OP’s example 2, which was “pointer = pointer”, still wouldn’t create a copy in that case and therefore work as they expected).

What about making things easier for him to understand, instead of confusing his head even further…
There’s no need to throw at him the whole bible when someone is asking about the basics.

In example 1:



int32 Number = 32;
int32* Pointer = &Number;


and what you’re doing here



*Pointer = *Pointer + 1;


The key is knowing the order in which the operators * and = are applied and knowing that = does based on the variable type. *Pointer is evaluated first, it “dereferences the pointer” and since its an int32 pointer, (*Pointer) is treated as an int32 value (at the address of Number, due to how its initialized). Now its time to interpret the =, since the left hand side is an int32, it will do the assignment operator for int32s which copies the right hand side of the assignment to the left hand side.



*Pointer = *Pointer + 1;
is equal to
(*Pointer) = ((*Pointer) + 1;)
and by looking at the types
(int32) = (int32 + int32);
the key is to know what = does for int32.


Now on to example 2



UInventory* PlayerInventory;
UInventory* LocalPlayerInventory = PlayerInventory;


I added the type of LocalPlayerInventory for clarity. LocalPlayerInventory’s type is an UInventory* (UInventory pointer). What is important now is to know what the assignment operator = does for pointers. Well, in fact it also copies the value, however in this case the copied value is the memory address. What you have is two different pointers, pointing at the same object (or memory address).

In short:
= in both examples makes a copy
However, when you copy a pointer, its still pointing to the same memory address a.k.a. object a.k.a. value.
You can treat both pointers as the same object until you change the value of either pointer (make it point to another object or make it null).

Edit:
I came up with an analogy that may help. The value is a dog and the pointer is a leash. When you copy a pointer, you duplicated the leash but put it on the same dog. You can pull the dog using either leash, until you decide to put either leash on a different dog. :stuck_out_tongue: