0

When I create a constructor for my class, C++ forces me to do two things:

  • Define rect as a pointer as I am using the new keyword.
  • As I defined it as a pointer I need to use the -> instead of the . to access their properties, methods.

My question is, why is it like that? I come from a Java background and it's not like that in Java, so I guess there is an advantage here I am not able to see. Can someone clarify this for me? And my apologies for the newbie question.

With constructor

// classes example
#include <iostream>
using namespace std;

class Rectangle {
    int width, height;
  public:
    void set_values (int,int);
    int area() {return width*height;}

  Rectangle(int w,int h) {
    width = w;
    height = h;
  }
};


int main () {
  Rectangle* rect = new Rectangle(5,8);

  cout << "area: " << rect -> area();
  return 0;
}

No constructor

// classes example
#include <iostream>
using namespace std;

class Rectangle {
    int width, height;
  public:
    void set_values (int,int);
    int area() {return width*height;}
};

void Rectangle::set_values (int x, int y) {
  width = x;
  height = y;
}

int main () {
  Rectangle rect;
  rect.set_values (3,4);
  cout << "area: " << rect.area();
  return 0;
}
melpomene
  • 84,125
  • 8
  • 85
  • 148
Matias Barrios
  • 4,674
  • 3
  • 22
  • 49
  • 3
    _"...forces me to do two things..."_ not true: change `Rectangle* rect = new Rectangle(5,8);` to `Rectangle rect{5,8};` – Richard Critten Mar 06 '18 at 19:45
  • you don't need to use `new` if you have [a constructor](http://en.cppreference.com/w/cpp/language/direct_initialization), also that code leaks memory. – Mgetz Mar 06 '18 at 19:45
  • 6
    c++ does not force you anything. You almost never need `new` (well not really but almost almost never ;). The question is rather unclear. Can you explain why you think that you must use `new` in the first case? – 463035818_is_not_an_ai Mar 06 '18 at 19:46
  • 2
    the presence of the constructor is a red herring. You can use `new` or not (cannot say often enough: you should not) whether you declare a constructor or not – 463035818_is_not_an_ai Mar 06 '18 at 19:48
  • 1
    you cannot translate your java knowlegde 1:1 to c++. Its not even close (despite the sometimes similar syntax), c++ works very different. Most prominently in c++ value semantics is prefered – 463035818_is_not_an_ai Mar 06 '18 at 19:49
  • 2
    suggest you this: https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – 463035818_is_not_an_ai Mar 06 '18 at 19:51
  • How about `Rectangle ret(5,8);`? – UKMonkey Mar 06 '18 at 19:58
  • Thanks to all. You have clarified this. Ill also have to read a book about c++ as posted by @user463035818. Greetings. – Matias Barrios Mar 06 '18 at 20:04

3 Answers3

2

On the notation used to access class members, there are some similarities between C++ and Java:

The a->b of C++ is normally equivalent to (*a).b. I say normally since it is possible in C++ to overload the pointer to member operator ->, whereas it's not possible to overload . (Although there is some movement in the C++ Standards Committee to relax that.)

As for the creation of instances of classes, complexities arise in C++ as, unlike Java, you have essentially two choices concerning class (and plain old data) type instantiation. You can use

  1. Automatic storage duration: Rectangle rect(1, 2);

  2. Dynamic storage duration: Rectangle* rect = new Rectangle(1, 2);

(A couple of other choices - static and thread_local have more of the first flavour.)

Note that in C++, unlike Java, you need to call delete to free the memory associated with the pointer that's been given to you by new. Some classes in C++ (e.g. std::unique_ptr) help a lot in managing that memory.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

You don't have to use pointers just because you have a constructor in your class. The two things are unrelated.

Your example of

Rectangle* rect = new Rectangle(5,8);

can easily be rewritten without pointers:

Rectangle rect(5,8);

Also note that Rectangle rect; still invokes a constructor: The default constructor (taking no arguments), Rectangle::Rectangle(). The compiler will generate a default constructor for you if you don't define a constructor yourself.

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • ok. get your point @melpomene. What would be the usage of the keyword "new" then? In Java I use that to create an instance of a class, in c++... – Matias Barrios Mar 06 '18 at 19:56
  • 1
    @MatiasBarrios `new` dynamically allocates an object (and returns a pointer to it). In C++ it's more about memory management than instantiating an object (but of course `new` does both). – melpomene Mar 06 '18 at 19:57
  • @MatiasBarrios I often wondered [whether Java needed a `new`keyword at all](https://stackoverflow.com/questions/6340535/is-the-new-keyword-in-java-redundant) – juanchopanza Mar 06 '18 at 19:59
  • 1
    `new` is a leftover from long ago. You don't need it anymore in any new code. In fact, if you do use it, you will get memory leaks because humans are incapable of mentally tracking all the dynamic allocations, and need a tool to do it for them. Use automatic storage duration, and abstractions like `std::unique_ptr` and `std::vector`. –  Mar 06 '18 at 19:59
  • 2
    @rightfold I agree that `new` is rarely justified in modern code. But to say *"you will get memory leaks because humans are incapable of mentally tracking all the dynamic allocation"* is quite the hyperbole. After all, people did manage for years before the wide spread use of RAII. – François Andrieux Mar 06 '18 at 20:04
0

The major difference (that's important here, anyway) between Java and C++ is memory management.

To a first approximation, in Java everything is an object allocated on the heap, and you access those objects via references (although they're more like C++ pointers than C++ references, and sometimes you may well see them called pointers). The exception is primitive types like int, which is why you can't create an ArrayList<int>. The system manages the lifetimes of objects for you using garbage collection; when nothing holds a reference to an object, it's collected.

C++ offers you more choice. One option is that you can allocate objects on the heap and access those objects via pointers, using the new keyword. So far, this is exactly the same as Java, which is probably why Java borrowed the use of the new keyword. The main difference here is that C++ doesn't keep track of the lifetime of those objects; you have to manually use the delete keyword when you want the object to be destroyed.

Alternatively, you can allocate on the stack, like so:

int main () {
  Rectangle rect(5,8);

  cout << "area: " << rect.area();
  return 0;
}

Note that this does use the constructor! In this case, the memory for that rect object isn't on the heap, it's on the stack. In some ways, it's now more like a primitive type like int; it lives only as long as it's in scope. Some people will use the term "value semantics" to describe things like this. When it drops out of scope, the object is destroyed.

There are some advantages and disadvantages of using the stack compared to the heap. One is that it's a lot faster to allocate memory on the stack than on the heap (allocating memory on the stack is pretty much done by incrementing a single pointer!); another is that the lifetime of a stack object is completely obvious. A disadvantage is that the stack has a relatively small amount of memory available; if you try to allocate too much on the stack, you're at risk of er... overflowing your stack.

One key thing to flag up here that's different in C++ to Java is that in Java, when an object is destroyed is determined by the garbage collector. From the point of view of a program, it's non-deterministic. This isn't the case with C++; objects are destroyed either when they drop out of scope (for stack-allocated objects) or when they're explicitly deleted (for objects on the heap). So this is why it makes sense for C++ to have destructors, because you know when they'll get called.

This is why C++ doesn't have anything like Java's try-with-resources/AutoCloseable (or, for that matter, IDisposable in C#); the destructor takes that role. If, for example, you use a std::ifstream to read from file, and you create that object on the stack, the file will be closed for you when the ifstream drops out of scope, and this holds true for any sort of scope; you don't need a special syntax like try-with-resources.

Now, the typical practice in C++ is to use things allocated on the stack (with value semantics) to provide abstractions to help you do memory management. Examples of this include std::vector<> and std::unique_ptr<>. The pattern of using objects with C++ value semantics to manage the lifetime of other resources (like memory, open files, locks on a mutex, etc.) is known as RAII.

So, to boil it down, the difference is that C++ has two different ways of allocating objects that have really different semantics (value/stack and reference/heap). Java (mostly) only has one (reference/heap). And despite them both having a . operator, the Java . operator behaves like the C++ -> operator, in that they access the fields of an object elsewhere via a pointer (C++) or reference (Java). They can actually both blow up in a similar way, if you try to use -> on a null pointer, or . on a null Java reference.

The C++ . operator accesses the fields of values. It does a different thing, which is why it's different.

aiusepsi
  • 354
  • 1
  • 5