I'm continuing my studies for uni with C++ and I'm running into some serious comprehension issues concerning pointers, const arguments and all the very basics of class implementations (which are so easy in Java compared to C++)
I usually work with Java, so C++ is very new to me.
This is my simple header for a class "Person":
#ifndef Person_h
#define Person_h
class Person
{
private:
char* name;
char* adress;
char* phone;
public:
Person();
Person(char const *name, char const *adress, char const *phone);
Person(const Person &other);
~Person();
void setName(char const *name);
char* getName() const;
void setAdress(char const *adress);
char* getAdress() const;
void setPhone(char const *phone);
char* getPhone() const;
};
#endif // !Person_h
And here the problem starts. Why should I use char pointers instead of actual char variables? I'm guessing it's some conventions to spare memory or to improve performance?
This is the way our professor codes and tries to make us understand the use of pointer and const
etc.
Now here's my implementation of the class:
#include "Person.h"
//Person.h class implementation
Person::Person()
{
Person::name = new (char[64]);
Person::adress = new (char[64]);
Person::phone = new (char[64]);
}
Person::Person(const char *name, const char *adress , const char *phone)
{
Person::name = new (char[64]);
Person::adress = new (char[64]);
Person::phone = new (char[64]);
setName(name);
setAdress(adress);
setPhone(phone);
};
Person::Person(Person const &other)
{
Person::name = new (char[64]);
Person::adress = new (char[64]);
Person::phone = new (char[64]);
setName(other.getName);
setAdress(other.getAdress);
setPhone(other.getPhone);
};
Person::~Person()
{
delete [] name;
delete [] adress;
delete [] phone;
};
void Person::setName(const char *name)
{
this->name = name;
};
char* Person::getName() const
{
return name;
};
void Person::setAdress(char const *adress)
{
this->adress = adress;
};
char* Person::getAdress() const
{
return adress;
};
void Person::setPhone(char const *phone)
{
this->phone = phone;
};
char* Person::getPhone() const
{
return phone;
};
We should learn to manually allocate memory to elements and try to take care of the overall memory management. Therefore the use of const arguments for the setter functions. I guess this is in order to not alter the element argument? I'm very confused, basically...
And my IDE (MS VisualStudio 2015) underlines the following line as error:
void Person::setName(const char *name)
{
this->name = name; //error
};
"a value of type 'const char *' cannot be assigned to an entity of type 'char *'"
Then why should I use const
when I can't assign these values? Or how can I "un-const" those, without making the member variable itself const
?
This whole matter is just one big confusion to me now.
EDIT: I have to use C-strings for my exams, that's in order to understand pointer and memory management referring to our prof.
In modern C++ you should be still aware of memory management, but for the sake of readability, exception safety and bugs you should use containters, which do the work for you, as std::string.
const char *name means, that you have a pointer, which points to a memory section, which itself is const, which means, that the data inside this memory section shouldn't change.
The pointer itself can change.
When you assign
you are just assigning a pointer this->name to the pointer of name. But this you can do only when the pointer are of convertible type. If you change the type of this->name from char* to type const char*, the compiler shouldn't complain.
But before you assign there anything new, you should clean up the memory, e.g. delete[] this->name
In layman's terms, the reason why
this->name = name;
does not work whenname
is const andthis->name
is non-const, is because your function is promising that the contents ofname
will be treated as read-only, but by assigning this pointer to a non-const pointer you would then be free to modify the data as you please, thus breaking your promise.Your teacher is obviously trying to teach you old-style C++ with pointers, (essentially, object-oriented C,) so you should not go ahead and replace char pointers with strings. Your teacher will probably be unhappy if you do that.
There is a number of reasons why we use
char*
instead ofchar[]
.One reason is efficiency: if it was possible to pass a
char[]
, then the entire contents of thatchar[]
would need to be copied to the stack. When you pass achar*
, you are only copying the pointer to the characters, which is usually a single machine word.Another reason is that it is actually impossible. The compiler has no built-in knowledge of the fact that your
char[]
is zero-terminated so as to allocate enough stack space for it and copy it to the stack. The creators of the language preferred to not put such built-in knowledge in the language. Instead, they decided that achar[]
should be implicitly converted tochar*
, so that from within your function you can receive it as achar*
and do what you want with it.Another reason is that if your
char[]
was just a bit too large, then your stack would overflow.So, for all these reasons, when we want to pass values of types that are larger (or considerably larger) than machine words, we do not pass the values themselves, we pass pointers or references to them.
Doing e.g.
is problematic for two reasons: First of all because of you trying to assign a variable of one type to a variable of a closely related but still different type. But that's not the big problem.
The big problem is that you attempt to reassign the original pointer
this->name
(which points to some memory you have allocated) with another pointer (which points somewhere else).The result is similar to
and then wondering why
a
is no longer equal to5
.There are two solutions here: The first one is keep using pointers and then copy the string instead of assigning pointers. This is done with the
std::strcpy
function.The solution I recommend though, is to stop using pointers for strings and instead use the standard C++
std::string
class. Then you can use simple assignment to copy strings. They also handle their own memory, so you don't have to worry about memory leaks, pointers, freeing invalid pointers or keeping track of the actual size of the strings.The
std::string
class of C++ shares some similarities with the JavaString
class, so if you come from a Java background it should not be hard for you to adjust. The biggest different is that in C++ usingstd::string
you actually can compare strings directly with==
.