1

I am learning C++. There is a curious case and I want to know the solution. Suppose the code is as following

class HumanBeing {
private:
    string *name;
    int *age;

    HumanBeing(string name, int age) {
        // what to do in here?
    }
};

In Java I can use this.name = name. But in C++ I can do this->name = name(it is not valid for above example), but what to do when the class variable is a pointer?

I am from Java background so these(pointers) things are very confusing for me.

Anirban Nag 'tintinmj'
  • 5,572
  • 6
  • 39
  • 59
  • 2
    Your example is a scenario where you would typically *not* choose to use pointer members at all. The pointer members would have a longer lifespan than the constructor parameters they would point to. – Drew Dormann Jul 22 '15 at 22:52
  • this->name is a pointer. You cannot assign this to a string (by value) – Jens Munk Jul 22 '15 at 22:52
  • @JensMunk so what can i write in the constructor to access the class variable `name`? – Anirban Nag 'tintinmj' Jul 22 '15 at 22:53
  • If you declared a pointer, that means that you want to make it to *point* somewhere. But no one here knows where you want it to point to. Only you do. Which is why it is unclear what you are asking. How do you expect up to know what you what to do? Explain what you want to achieve as the end result of all this, and them maybe we'll be able to tell you how to do it. – AnT stands with Russia Jul 22 '15 at 22:54
  • @AnirbanNag'tintinmj' You could change your member to a std::string name and do exactly what you already did. It will work – Jens Munk Jul 22 '15 at 22:56
  • "I am from Java background so these(pointers) things are very confusing for me." Your Java background is perfect to understand pointers! Java has pointers (sometimes called 'Java references') and they behave the same as C/C++ pointers. So don't worry, you already know very well how to use C/C++ pointers! But it's better, and easier, to just avoid pointers and pass things by value in most cases. But Java doesn't have this easy option, so perhaps it will take you a little time to get used to it. Welcome to C++!! – Aaron McDaid Jul 22 '15 at 23:01
  • @AaronMcDaid no, java object references do not behave like C++ pointers – M.M Jul 22 '15 at 23:08
  • 1
    @AnirbanNag'tintinmj' In C++ you should not use pointers in your class definition here. They don't do what you think they do . – M.M Jul 22 '15 at 23:09
  • 1
    @AnirbanNag'tintinmj' There is no need for pointers. Just declare a `string` and `int` member, as any sane C++ programmer would. Look at the answers and all of issues associated with writing code like this. Also, don't use Java as a guide in writing C++ code. Maybe that is where you are going astray. – PaulMcKenzie Jul 22 '15 at 23:11

5 Answers5

11

I would avoid using pointers in this example and rewrite it like this:

class HumanBeing {
private:
    string name;
    int age;
public:
    HumanBeing(string name, int age) : name (name), age (age) 
    {
    }
};

The above example initializes you data members using a constructor initialization list.

If you choose to use pointers anyway, then you have to decide how owership of the data will be handled.

If your class will take ownership of the data, then you can do what tp1 suggested.

If your class will not take ownership of the data, then you can do this:

    HumanBeing(string &name, int &age) : name (&name), age (&age) 
    {
    }

If you have access to C++11 and still want to use pointers, I would suggest at least using smart pointers.

Community
  • 1
  • 1
6

try

this->name = new string(name);
this->age = new int(age);

But I would recommend renaming the parameters so that there is no confusion whether you use the parameter or member variable.

tp1
  • 1,197
  • 10
  • 17
  • 7
    And now you have the issue of `delete` and memory leaks. – PaulMcKenzie Jul 22 '15 at 23:13
  • 2
    Since the OP claims to come from Java, and since this is C++, a huge caveat should be given with this solution. The class now requires that the rule of 3 be implemented: http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three C++ has no garbage collection to release the memory. – PaulMcKenzie Jul 22 '15 at 23:23
4

Your logic is correct. You should be able to write this->name = name. I believe your problem is that the class variable 'name' is pointer to string string * while the parameter you're receiving in your constructor is a string string. Try changing this:

private:
  string *name;
  int *age;

To this:

private:
  string name;
  int age;

UPDATE: If you want to use pointers then you must pass a pointer.

MyClass(string *name, int *age)
{
  this->name = name;
  this->age = age;
}

Or you could pass by reference and have a similar behavior to Java.

private:
  string *name;
  int *age;

MyClass(string &name, int &age)
{
  this->name = &name;
  this->age = &age;
}

Thanks @user007

Pepedou
  • 787
  • 1
  • 13
  • 35
  • Yes I am aware of that `name` is a string pointer. I don't want to change it. That's why the 'curious case' I mentioned. – Anirban Nag 'tintinmj' Jul 22 '15 at 22:58
  • @AnirbanNag'tintinmj', why do want want to use pointers as members in this way? It's not good C++. – Aaron McDaid Jul 22 '15 at 22:59
  • @AaronMcDaid It's for experimental purpose. – Anirban Nag 'tintinmj' Jul 22 '15 at 23:00
  • If you're using pointers store the address of the parameter with the & operator or pass a pointer as a parameter. I updated my answer to show both scenarios. – Pepedou Jul 22 '15 at 23:02
  • @AnirbanNag'tintinmj' There is very little to experiment with. You assign a pointer with a pointer. Given that, there is no need to write code like this. – PaulMcKenzie Jul 22 '15 at 23:03
  • @Pepedou Your last example leads to undefined behavior. You are assigning the address of a temporary to the instance. – PaulMcKenzie Jul 22 '15 at 23:04
  • @Pepedou The second option of your updated answer is giving negative exit value. – Anirban Nag 'tintinmj' Jul 22 '15 at 23:05
  • Your 2nd constructor in the **UPDATE** portion is wrong! You are passing `name` and `age` by value! So, a copy of them is sent! So by the time your function call gets over `name` and `age` are removed from the stack and they don't exist (which is undefined behaviour)! – user007 Jul 22 '15 at 23:06
  • @Pepedou you need not remove it! It can be changed to this! `MyClass(string &name, int &age)` this way it will work fine! – user007 Jul 22 '15 at 23:07
  • @user007 Then it makes the class very fragile – M.M Jul 22 '15 at 23:08
  • @user007 I was just thinking about adding that but wasn't sure because he said he wants to use pointers as member variables. – Pepedou Jul 22 '15 at 23:10
  • @MattMcNabb Fragile? Why? Can you explain a bit? – user007 Jul 22 '15 at 23:10
  • 1
    @Pepedou yeah! Then we can use `this->name = &name` address of the reference would give the address of the original string! – user007 Jul 22 '15 at 23:13
  • 2
    @user007 imagine someone writes: `string s("bla");` and then `new HumanBeing(s);` (assigned to an appropriate sort of pointer). Then `s` may end its lifetime , leaving the dynamically allocated HumanBeing with a dangling reference. – M.M Jul 22 '15 at 23:13
  • @MattMcNabb Yeah! But that will be the case even when we pass the parameters by pointers, right? So the whole thing of storing it as pointer is wrong I assume. – user007 Jul 22 '15 at 23:17
  • 1
    @user007 Yes; although when the parameters are pointers it does give the programmer writing the calling code a bit of a hint that the class might store the pointer. – M.M Jul 22 '15 at 23:20
2

HumanBeing is a constructor. Whenever possible, you should use the base/member initializer syntax of a constructor to initialize the members and base class portions:

HumanBeing(string name, int age)
: name(name)  // error!
, age(age)    // error!
{
    // what to do in here? Nothing!
}

However, that won't work here (see error! comments) because the members age and name are pointers.

This is a problem, because the constructor arguments are temporary objects. We must not store, inside the class object, pointers to temporary objects. And so we cannot fix it like this, even though it compiles:

HumanBeing(string name, int age)
: name(&name) 
, age(&age)
{
}

The parameter objects name and age cease to exist when the constructor terminates, and so the object's members are left pointing to garbage.

You must redesign the constructor with a different interface, or redesign the class so that its members aren't pointers.

// Alternative constructor: get stable objects from somewhere

HumanBeing(string *n, int *a) : name(n) , age(a) { }

// Alternative class design

class HumanBeing {
private:
    string name;
    int age;

    HumanBeing(string n, int a)
    : name(n)
    , age(a)
    {
    }
};

There is rarely any need to fuss around with the this pointer. The main use is when a non-static member function needs to call another function in another class, or a non-class function, and needs to pass a pointer to its object. For instance:

// FooClass derives from NotificationTarget
// The this pointer is FooClass *, and
// implicitly converts to NotificationTarget * in the RegisterMe call.

FooClass::RegisterForNotification(NotificationSource &ns)
{
  ns.RegisterMe(this);   // void NotificationSource::RegisterMe(NotificationTarget *);
}

The this pointer can be used to overcome a scoping problem in C++:

int xl;  // at file scope

class funny {
  int x1;

  void method()
  {
     xl = 1;  // TYPO! assigns to xl at file scope, not x1 member.
     this->xl = 1; // TYPO! But caught by compiler. 
  }
};

This doesn't add up to a reason to use this->member all over the place in C++ programs; you must use sane naming conventions to defend against this type of problem, such as using g_ prefix on globals, and m_ on members, or a similar convention.

Kaz
  • 55,781
  • 9
  • 100
  • 149
2

Pointers are just variables that hold a memory address. They do not hold any data value, they just hold a memory address to the data. Don't think of them as something too complicated.

class HumanBeing {
private:

    // just holds a memory address (size 4 for 32-bits, 8 for 64 bits)
    string *name;

    // just holds a memory address (size 4 for 32-bits, 8 for 64 bits)
    int *age;

    HumanBeing(string name, int age) {
        // These lines use new to allocate memory from the heap and
        // initialize them with the parameters passed.
        // Then they return memory addresses that are stored in
        // this->name and this->age
        this->name = new string(name);
        this->age = new int(age);
    }
};

If you want to use pointers in more code: this->name is a memory address *(this->name) dereferences that memory address and gives the value where that memory address is located.

Also beware anytime you use new, you have to delete the allocated memory to prevent memory leaks when you're not using it anymore because C++ doesn't have the convenient resource expensive garbage collector that Java has.