C++ pointer vs object - c++

Could you please clear up a question for me regarding pointer vs object in C++. I have the below code that has a class called "person" and a list that allows for 100 objects of that class type.
class person {...}
int main {
person* mylist;
mylist = new person[100];
mylist[0].set_name("John")
// ...
}
In this code I can call a method of the class by mylist[0].set_name() meaning (by my understanding) that mylist[0] is an object (hence the . operator to call a method). The code works fine.
I have another project where the "person" class is used as a base class to derive classes "carpenter" and "welder". The derived classes simply overwrite a virtual function called salary in the base "person" class to allow for a different calculation of salary.
person* mylist[100];
mylist[0] = new carpenter;
mylist[0]->set_name("John");
This code works fine as well. My question is - why in the first code I can call the set_name method using the . (meaning mylist[0] is an object) and in the second code I have to use the -> operator (meaning mylist[0] is a pointer to the object)?

T* represents a pointer type, which represents a variable that contains a "reference" (usually a memory address) to some instance of type T. Using a real world comparison, a T* pointer stands to T like a street address stands to a building.
Pointers allow you to refer to some instance owned by some other variable, and you can use a valid, non null instance of T* to read and write on a T. In this, they are similar to another C++ concept, references (written as T&), which allow you to alias variables, but differ significantly from pointers by not being objects in their own regard.
A pointer is, in fact, an object itself, with each pointer variable having its own unique address and being thus storable and referenceable. For instance, you can have pointers to pointers (T**) and references to pointers (T*&), but not pointers to references - pointers exist, while references may not (they are usually implemented as pointers underneath though).
To reflect the this "indirect" nature of pointers, C and C++ provide you with two different operators which allow you to dereference a pointer (* and ->), and to reference a variable (&).
For instance, you may do the following:
struct A { int x; };
// ...
A a {};
A *aptr { &a }; // `&` takes the address of `a` and stores it into the `aptr` variable of type `A*`
aptr->x = 33; // `->` is equivalent here to `(*aptr).x`, a.x is now 33
A a2 {};
A **aptrptr { &aptr }; // pointer to pointer
*aptrptr = &a2; // `aptr` now points to `a2`
operator-> is basically syntactic sugar that avoids you some cumbersome expressions like (*aptr).x.
References, being basically just aliases to something else, do not need any special syntax at all, and are always converted transparently when neeeded:
int x { 33 };
int &xref { x }; // `xref` refers to `x`
xref = 12; // `x` is now 33
int y = xref; // copies `x` into `y`, no special syntax needed
Pointers are also used in the C language to access arrays, which always decay to a pointer as soon as they are referred to in expressions. This is messy and it's one of the reasons std::vector and std::array should always be used in their place when feasible.
int x[33];
x[3] = 44; // equivalent to `*(&x[0] + 3) = 44`
Finally, the "indirect" nature of pointers and references allow C++ to convert a Derived* to a Base*, given that a derived class contains a full instance of its base (it gets more complicated with multiple inheritance though).
Every class that inherits or contains from another class containing virtual methods will include a hidden pointer to a _Virtual Method Table`, a list of pointers to functions which will be used to dispatch the virtual methods to the correct implementation.
PS: in modern C++, you should rarely need raw pointers. The correct approach is to use containers such as std::vector, std::array and std::string, and special pointer-like wrappers called smart pointers (like std::unique_ptr) every time you need a pointer for some reason. These will handle the lifetime of a pointer for you, avoiding memory leaks and vastly simplifying memory handling. For the same reason, the new operator should be mostly considered as being deprecated and should not be used at all (unless in placement new expressions, are potentially dangerous if used improperly).

basically the first case works like this: you have an array of objects. To access the object fields and methods you use . operator.
In the second case you have an array of pointers to an object. Pointer is just a memory address, that points to an object of some type. In your case, this is an array of pointers to class person. By default, these pointers are invalid; you have to set them to the address of some existing object. new creates an object on the heap, and returns you an address of that object. In order to access the value behind the pointer, you have to de-reference it. The syntax is this:
some_type obj;
some_type* ptr = &obj; // get the address of the object
(*ptr).some_method(); // de-reference the pointer and call it
ptr->some_method(); // same

Related

Storing a reference within class

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.

How to Create a Constant Reference to an Object?

I have a design which includes 3 classes as my data structures. Let's call the classes A, B, and C.
I have to instantiate objects of A, B, and C while parsing my input. Each object of class C needs to keep track of the corresponding objects in classes A and B. My current implementation looks like this:
class C {
private:
A* a;
B* b;
public:
void setA(A* a);
void setB(B* b);
}
I assign a and b when I create the objects of A and B using new operator. The problem is that I do not want an object of class C to be able to modify a and b. In fact, I only need to know which a and b correspond to a specific c.
One solution could be to define a and b as const pointers/object references. However, in the case of object references, I need to define them as soon as I declare them. The problem is that I am parsing several files and I cannot assign the proper references to a and b when I define them. In other words, a and b are created at different times in my program and may not be available when I create c.
Recently, I read that it's better to avoid raw pointers as much as possible and that's why I'm trying to implement this using object references instead of pointers. Actually, this is giving me a hard time to figure out which one to use at different stages of my program.
My questions are as follows:
1) Is it better to use object references instead of pointers in this specific question?
2) While this approach works for pointers, what should I do to assign constant references to a and b if I prefer to use object references instead of pointers?
3) If I use unique_ptr for a and b, what would be the solution to this problem?
It is good modern C++ style to avoid using raw pointers. See
Chapter 4 of Effective Modern C++ by Scott Meyers for details.
However, this doesn't mean you cannot use pointers. I'd also recommend the reading Effective C++, More Effective C++, and Effective STL.
So nomenclature wise, the reference or pointer are both pointing
to the same object. Under the covers, you are copying around memory
addresses of the object in question.
Now to use a const pointer (or reference) the object itself doesn't
have to be const. If the function takes a const type* or const
type&, the type system will tack on the const for you.
What I think you want is a const pointer. Here the item being
pointed to is const, and not the memory address, so you do not have
to initialize the parameters on construction. Issue with the const
reference is what would you initialize it as? The const type* can
be set to nullptr on construction, but a reference doesn't have a
way to have a null value. I'd say this is important here because
you will want to be able t tell if the caller assigned a value to a
or b. If they didn't, and you properly initialized the member
variables to nullptr, you can test against that to know they weren't
set.
So in this case, the actual memory to be owned by a
std::unique_ptr<> and you would pass down a reference or pointer to
the object. In your situation, sending down the address/pointer is
the only reasonable thing to do. you'll want to initialize the
value to nullptr on construction. Then you'll be able to tell if
the caller assigned a value, because the pointer is not null. If
you wanted to use a const type&, you'd have to set a valid value at
construction time, and since their is no null&, their is no obvious
way to do it.
Also, though this wasn't part of your question, I would document who really owns the memory. One thing I like about using std::unique_ptr<> is that is makes ownership obvious.
Your updated example:
class C {
private:
const A* a;
const B* b;
public:
void setA(const A* a);
void setB(const B* b);
}
The problem is that I do not want an object of class C to be able to modify a and b. In fact, I only need to know which a and b correspond to a specific c.
Use a const pointer:
A const* a;
A const* b;
Then deference them, and they will be objects.
Use pointers instead of references, as if you have an instance of C in either class A or B, you will get an error. Using pointers avoids that
(1)It does not matter; you should use pointers because it is easier to see when you are passing a reference. For example:
function(a); // Not sure if it is a reference
function(&a); // You know it is that actual object
(2) Deference the const pointer, and it will make it a const "reference"

unique_ptr and polymorphism

I have some code that currently uses raw pointers, and I want to change to smart pointers. This helps cleanup the code in various ways. Anyway, I have factory methods that return objects and its the caller's responsibility to manager them. Ownership isn't shared and so I figure unique_ptr would be suitable. The objects I return generally all derive from a single base class, Object.
For example,
class Object { ... };
class Number : public Object { ... };
class String : public Object { ... };
std::unique_ptr<Number> State::NewNumber(double value)
{
return std::unique_ptr<Number>(new Number(this, value));
}
std::unique_ptr<String> State::NewString(const char* value)
{
return std::unique_ptr<String>(new String(this, value));
}
The objects returned quite often need to be passed to another function, which operates on objects of type Object (the base class). Without any smart pointers the code is like this.
void Push(const Object* object) { ... } // push simply pushes the value contained by object onto a stack, which makes a copy of the value
Number* number = NewNumber(5);
Push(number);
When converting this code to use unique_ptrs I've run into issues with polymorphism. Initially I decided to simply change the definition of Push to use unique_ptrs too, but this generates compile errors when trying to use derived types. I could allocate objects as the base type, like
std::unique_ptr<Object> number = NewNumber(5);
and pass those to Push - which of course works. However I often need to call methods on the derived type. In the end I decided to make Push operate on a pointer to the object stored by the unique_ptr.
void Push(const Object* object) { ... }
std::unique_ptr<Object> number = NewNumber(5);
Push(number.get());
Now, to the reason for posting. I'm wanting to know if this is the normal way to solve the problem I had? Is it better to have Push operate on the unique_ptr vs the object itself? If so how does one solve the polymorphism issues? I would assume that simply casting the ptrs wouldn't work. Is it common to need to get the underlying pointer from a smart pointer?
Thanks, sorry if the question isn't clear (just let me know).
edit: I think my Push function was a bit ambiguous. It makes a copy of the underlying value and doesn't actually modify, nor store, the input object.
Initially I decided to simply change the definition of Push to use
unique_ptrs too, but this generates compile errors when trying to use
derived types.
You likely did not correctly deal with uniqueness.
void push(std::unique_ptr<int>);
int main() {
std::unique_ptr<int> i;
push(i); // Illegal: tries to copy i.
}
If this compiled, it would trivially break the invariant of unique_ptr, that only one unique_ptr owns an object, because both i and the local argument in push would own that int, so it is illegal. unique_ptr is move only, it's not copyable. It has nothing to do with derived to base conversion, which unique_ptr handles completely correctly.
If push owns the object, then use std::move to move it there. If it doesn't, then use a raw pointer or reference, because that's what you use for a non-owning alias.
Well, if your functions operate on the (pointed to) object itself and don't need its address, neither take any ownership, and, as I guess, always need a valid object (fail when passed a nullptr), why do they take pointers at all?
Do it properly and make them take references:
void Push(const Object& object) { ... }
Then the calling code looks exactly the same for raw and smart pointers:
auto number = NewNumber(5);
Push(*number);
EDIT: But of course no matter if using references or pointers, don't make Push take a std::unique_ptr if it doesn't take ownership of the passed object (which would make it steal the ownership from the passed pointer). Or in general don't use owning pointers when the pointed to object is not to be owned, std::shared_ptr isn't anything different in this regard and is as worse a choice as a std::unique_ptr for Push's parameter if there is no ownership to be taken by Push.
If Push does not take owenrship, it should probably take reference instead of pointer. And most probably a const one. So you'll have
Push(*number);
Now that's obviously only valid if Push isn't going to keep the pointer anywhere past it's return. If it does I suspect you should try to rethink the ownership first.
Here's a polymorphism example using unique pointer:
vector<unique_ptr<ICreature>> creatures;
creatures.emplace_back(new Human);
creatures.emplace_back(new Fish);
unique_ptr<vector<string>> pLog(new vector<string>());
for each (auto& creature in creatures)
{
auto state = creature->Move(*pLog);
}

How are pointers to data members allocated/stored in memory?

This is one topic that is not making sense to me. Pointers to data members of a class can be declared and used. However,
What is the logic that supports the idea ? [I am not talking about the syntax, but the logic of this feature]
Also,if i understand this correctly, this would imply an indefinite/variable amount of memory being allocated at the pointer initialization as any number of objects may exist at that time. Also, new objects may be created and destroyed during runtime. Hence, in effect, a single statement will cause a large number of allocations/deallocations. This seems rather counter-intuitive as compared to the rest of the language. Or is my understanding of this incorrect ? I dont think there is any other single initialization statement that will implicitly affect program execution as widely as this.
Lastly, how is memory allocated to these pointers ? Where are they placed with respect to objects ? Is it possible to see physical memory addresses of these pointers ?
A single declaration of a pointer to a data member, creates pointers for every object of that class.
No, it does not. A pointer to a member is a special object that is very different from a pointer; it is a lot more similar to an offset. Given a pointer to an object of the class and a member pointer, you'd be able to get the value of a member; without the pointer to an object of a class a pointer to a member is useless.
Questions 2 and 3 stem from the same basic misunderstanding.
A single declaration of a pointer to a data member, creates pointers for every object of that class.
No. It creates a pointer to a member (which can be though of as an offset from the base of object)
You can then use it with a pointer to an object to get that member.
struct S
{
int x;
int y;
};
int S::* ptrToMember = &S::x; // Pointer to a member.
S obj;
int* ptrToData = &obj.x; // Pointer to object
// that happens to be a member
Notice in creating the pointer to a member we don't use an object (we just use the type information). So this pointer is an offset into the class to get a specific member.
You can access the data member via a pointer or object.
(obj.*ptrToMember) = 5; // Assign via pointer to member (requires an object)
*ptrToData = 6; // Assign via pointer already points at object.
Why does this happen as opposed to a single pointer being created to point to only one specific instance of the class ?
That is called a pointer.
A similar but parallel concept (see above).
What is the logic that supports the idea ?
Silly example:
void addOneToMember(S& obj, int S::* member) { (obj.*member) += 1; }
void addOneToX(S& obj) { addOneToMember(obj, &Obj::x);}
void addOneToY(S& obj) { addOneToMember(obj, &Obj::y);}
Also,if i understand this correctly, this would imply an indefinite/variable amount of memory being allocated at the pointer initialization as any number of objects may exist at that time.
No. Because a pointer to a member is just an offset into an object. You still need the actual object to get the value.
Lastly, how is memory allocated to these pointers ?
Same way as other objects. There is nothing special about them in terms of layout.
But the actual layout is implementation defined. So there is no way of answering this question without referring to the compiler. But it is really of no use to you.
Is it possible to see physical memory addresses of these pointers ?
Sure. They are just like other objects.
// Not that this will provide anything meaningful.
std::cout.write(reinterpret_cast<char*>(&ptrToMember), sizeof(ptrToMember));
// 1) take the address of the pointer to member.
// 2) cast to char* as required by write.
// 3) pass the size of the pointer to member
// and you should write the values printed out.
// Note the values may be non printable but I am sure you can work with that
// Also note the meaning is not useful to you as it is compiler dependent.
Internally, for a class that does not have virtual bases, a pointer-to-member-data just has to hold the offset of the data member from the start of an object of that type. With virtual bases it's a bit more complicated, because the location of the virtual base can change, depending on the type of the most-derived object. Regardless, there's a small amount of data involved, and when you dereference the pointer-to-data-member the compiler generates appropriate code to access it.

Trying to store an object in an array but then how to call that object's methods?

I'm not a very experienced c++ coder and this has me stumped. I am passing a object (created elsewhere) to a function, I want to be able to store that object in some array and then run through the array to call a function on that object. Here is some pseudo code:
void AddObject(T& object) {
object.action(); // this works
T* objectList = NULL;
// T gets allocated (not shown here) ...
T[0] = object;
T[0].action(); // this doesn't work
}
I know the object is passing correctly, because the first call to object.action() does what it should. But when I store object in the array, then try to invoke action() it causes a big crash.
Likely my problem is that I simply tinkered with the .'s and *'s until it compiled, T[0].action() compliles but crashes at runtime.
The simplest answer to your question is that you must declare your container correctly and you must define an appropriate assigment operator for your class. Working as closely as possible from your example:
typedef class MyActionableClass T;
T* getGlobalPointer();
void AddInstance(T const& objInstance)
{
T* arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **objects**
//whose first element we don't mind losing
//**copy** the instance we've received
arrayFromElsewhere[0] = objInstance;
//now invoke the action() method on our **copy**
arrayFromElsewhere[0].action();
}
Note the signature change to const reference which emphasizes that we are going to copy the original object and not change it in any way.
Also note carefully that arrayFromElsewhere[0].action() is NOT the same as objInstance.action() because you have made a copy — action() is being invoked in a different context, no matter how similar.
While it is obvious you have condensed, the condensation makes the reason for doing this much less obvious — specifying, for instance, that you want to maintain an array of callback objects would make a better case for “needing” this capability. It is also a poor choice to use “T” like you did because this tends to imply template usage to most experienced C++ programmers.
The thing that is most likely causing your “unexplained” crash is that assignment operator; if you don't define one the compiler will automatically generate one that works as a bitwise copy — almost certainly not what you want if your class is anything other than a collection of simple data types (POD).
For this to work properly on a class of any complexity you will likely need to define a deep copy or use reference counting; in C++ it is almost always a poor choice to let the compiler create any of ctor, dtor, or assignment for you.
And, of course, it would be a good idea to use standard containers rather than the simple array mechanism you implied by your example. In that case you should probably also define a default ctor, a virtual dtor, and a copy ctor because of the assumptions made by containers and algorithms.
If, in fact, you do not want to create a copy of your object but want, instead, to invoke action() on the original object but from within an array, then you will need an array of pointers instead. Again working closely to your original example:
typedef class MyActionableClass T;
T** getGlobalPointer();
void AddInstance(T& objInstance)
{
T** arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **pointers**
//whose first element we don't mind losing
//**reference** the instance we've received by saving its address
arrayFromElsewhere[0] = &objInstance;
//now invoke the action() method on **the original instance**
arrayFromElsewhere[0]->action();
}
Note closely that arrayFromElsewhere is now an array of pointers to objects instead of an array of actual objects.
Note that I dropped the const modifier in this case because I don’t know if action() is a const method — with a name like that I am assuming not…
Note carefully the ampersand (address-of) operator being used in the assignment.
Note also the new syntax for invoking the action() method by using the pointer-to operator.
Finally be advised that using standard containers of pointers is fraught with memory-leak peril, but typically not nearly as dangerous as using naked arrays :-/
I'm surprised it compiles. You declare an array, objectList of 8 pointers to T. Then you assign T[0] = object;. That's not what you want, what you want is one of
T objectList[8];
objectList[0] = object;
objectList[0].action();
or
T *objectList[8];
objectList[0] = &object;
objectList[0]->action();
Now I'm waiting for a C++ expert to explain why your code compiled, I'm really curious.
You can put the object either into a dynamic or a static array:
#include <vector> // dynamic
#include <array> // static
void AddObject(T const & t)
{
std::array<T, 12> arr;
std::vector<T> v;
arr[0] = t;
v.push_back(t);
arr[0].action();
v[0].action();
}
This doesn't really make a lot of sense, though; you would usually have defined your array somewhere else, outside the function.