C++ const arguments in functions

2019-08-23 17:26发布

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.

3条回答
地球回转人心会变
2楼-- · 2019-08-23 17:56

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

this->name = name;

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

查看更多
祖国的老花朵
3楼-- · 2019-08-23 18:00

In layman's terms, the reason why this->name = name; does not work when name is const and this->name is non-const, is because your function is promising that the contents of name 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 of char[].

  • One reason is efficiency: if it was possible to pass a char[], then the entire contents of that char[] would need to be copied to the stack. When you pass a char*, 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 a char[] should be implicitly converted to char*, so that from within your function you can receive it as a char* 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.

查看更多
SAY GOODBYE
4楼-- · 2019-08-23 18:02

Doing e.g.

this->name = name;

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

int a = 5;
int b = 10;
a = b;

and then wondering why a is no longer equal to 5.

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 Java String 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++ using std::string you actually can compare strings directly with ==.

查看更多
登录 后发表回答