boost::shared_ptr question. Why does this work? - c++

In experimenting with this question I created an example that I utterly do not understand. In particular, it highlights my misunderstanding of pointers, references, and the boost::shared_ptr.
int& r = *(new int(0));//gratuitous pointer leak, got to initialize it to something
{
boost::shared_ptr<int> sp(new int(100));
r = *sp;
cout << "r=" << r << endl;
}
cout << "r=" << r << endl << endl;
int* p;
{
boost::shared_ptr<int> sp(new int(100));
p = &*sp;
cout << "*p=" << *p << endl;
}
cout << "*p=" << *p << endl;
Running this code gives an output something like this:
r=100
r=100
*p=100
*p=13
Why does the reference survive the death of the shared_ptr but the pointer does not?
There's a problem in the answers here in that there seem to be two diametrically opposed and contradictory solutions and no consensus upon which is the truth. I would like the ability to use a reference after a shared_ptr is deleted, but if it's invalid I really need to understand this.
Perhaps someone can post a simple example that demonstrates the undefined behavior in the reference.

Because r = *sp; does not do what you think it does. It assigns to the referent, that is, to the anonymous int object you created on the heap in line 1. You cannot reseat references in C++.
Here is what the standard says about evaluating reference expressions:
If an expression initially has the type "reference to T",
the type is adjusted to T prior to any further analysis.
The expression designates the object or function denoted by the reference,
and the expression is an lvalue or an xvalue, depending on the expression.
So you see, there is no way to get to "the reference itself". It simply does not exist in C++.
Maybe this code will make it clearer:
int a = 42;
int b = 97;
int&r = a; // r is just an alias (another name) for a
r = b; // assigns b to a (does NOT bind r to b, that's impossible in C++!)
After executing the last line, both a and b contain 97, because r = b really means a = b.

p is undefined, r is a copy
int& r = *(new int(0));
{
boost::shared_ptr<int> sp(new int(100));
r = *sp; // copy
cout << "r=" << r << endl;
}
cout << "r=" << r << endl << endl;
int* p;
{
boost::shared_ptr<int> sp(new int(100));
p = &*sp;
cout << "*p=" << *p << endl;
}
cout << "*p=" << *p << endl; // Undefined, pointer points to deleted int

In the second case, your int-object is destructed. In the first case it is not.
In the first case, you create a new int-object with new in the outer scope. In the inner scope, you create a second int-object, for which you also create a shared_ptr, which then owns the int-object. This shared_ptr runs out of scope when you close the inner scope, it therefore gets destructed. The shared_ptr destructor will also destruct the object it refers to, because no other shared_ptr (that was created from the original one) refers to your int object anymore. That's all alright. However, in the middle of that scope you re-assign the value of r to that of *sp (100). You therefore save the value of *sp, before sp gets destructed, into r.
Note: it's certainly questionable style to create an int object the way you do it in your first line of code. If you don't explicitly delete that int object, this is a memory leek. The way to destruct it would be delete &r which looks really ugly, especially because the symbol r afterwards still refers to the, now deleted, int object. DON'T DO THIS!
In the second case you create an int pointer at the beginning, but no int object. The inner scope is almost the same as before, except that this time you do not save the value of your new int object into the outer-scope variable (p), but you save the address of the int object! As the int object gets destructed at the end of the inner scope (for the same reason as previously), p no longer points to an existing int object, but to a place in memory which formerly once hold an int object. The value you get from *p is undefined: you might still get 100, you could get any other value, and you might even crash your programme here (Segmentation fault) as you dereference a memory location you no longer hold.
So to summarise, and answer your final question:
The reference survives, because it still refers to an existing object. The pointer does not, because it points to a no longer existing object.

Related

C++ map, use const reference as value type, what is the problem here?

Today I saw my boss's code which uses a const reference as a map's value type.
Here's the code:
class ConfigManager{
public:
map<PB::Point, const PB::WorldPoint&, compare_point> world_point;
//the rest are omitted
};
(PB is Google Protobuf, we are using the Protobuf library. I don't know much about it or if it's relevant to the question. )
What this class does is that it reads some config files and put it into some maps for searhing.
At first I was surprised because I haven't seen a map with a reference as its value, which is e.g. map<int, classA&> aMap.
So then I searched on SO and these 2 questions tell me that I can't do that.
C++: Is it possible to use a reference as the value in a map?
STL map containing references does not compile
Then I tried this code, indeed it doesn't compile:
Code Example1
struct A {
int x = 3;
int y = 4;
};
map<int, A&> myMap;
int main() {
A a;
myMap.insert(make_pair(1, a));
}
But if I change map<int, A&> myMap; to map<int, const A&> myMap;, it compiles.
Yet another problem occured. With map<int, const A&> myMap;, I can't use [] to get the pair, but I can use map.find().
(My boss told me to use map.find() after I told him using[] can't compile).
Code Example2
struct A {
int x = 3;
int y = 4;
};
map<int, const A&> myMap;
int main() {
A a;
myMap.insert(make_pair(1, a));
//can't compile
cout << myMap[1].x << " " << myMap[1].y << endl;
//can work
//auto it = myMap.find(1);
//cout << it->second.x << " " << it->second.y << endl;
}
So till here I was thinking my boss was correct. His code was correct.
The last story is that I showed the code to some online friends. And they noticed a problem.
Code Example3
#include <map>
#include <iostream>
#include <string>
using namespace std;
struct A {
int x = 3;
int y = 4;
~A(){
cout << "~A():" << x << endl;
x = 0;
y = 0;
}
};
map<string, const A&> myMap;
int main() {
A a;
cout << a.x << " " << a.y << endl;
myMap.insert(make_pair("love", a));
a.x = 999;
cout << "hello" << endl;
auto s = myMap.find("love");
cout << s->second.x << " " << s->second.y << endl;
}
The output is:
3 4
~A():3
hello
0 0
~A():999
If I understand the output correctly(correct me if I get it wrong), it indicates that:
make_pair("love", a) creates an object pair<"love", temproray copy of a>. And the pair gets inserted into myMap.
Somehow, I don't know how it happens, the temporary copy of a gets destructed immediately. To me, it means the memory of the temporary copy of a is now not owned by anyone and it is now a free space of memory that can be filled with any values, if I understand correctly.
So now I am getting confused again.
My questions are:
What happens to the Code Example3? Is my understanding correct? Why does temporary copy of a get destructed right after the statement? Isn't using a const reference can extend a temporary's lifetime? I mean, I think the it should not get destructed till main finishes.
Is my boss's code incorrect and very dangerous?
Why does temporary copy of a get destructed right after the statement?
Because (in most cases) that's how temporaries work. The live until the end of the statement in which they are created. The extension to a temporaries lifetime doesn't apply in this case, see here. The TLDR version is
In general, the lifetime of a temporary cannot be further extended by
"passing it on": a second reference, initialized from the reference to
which the temporary was bound, does not affect its lifetime.
can I use const reference as a map's value type?
Yes as long as you realise that adding a const reference to a map has no effect on the lifetime of the object being referred to. Your bosses code is also incorrect because the temporary returned by make_pair is destroyed at the end of the statement.
You may use std:: unique_ptr<A> instead. Then emplace instead of insert:
using value_t=std:: unique_ptr<A>;
std::map<int, value_t> myMap;
myMap.emplace(1,new A);
myMap[1]=new A{5,6};
myMap[1]->x=7;
more on std:: unique_ptr<A>:
https://en.cppreference.com/w/cpp/memory/unique_ptr
What happens to the Code Example3? Is my understanding correct?
Your explanation is close. The std::pair that is returned by std::make_pair is the temporary object. The temporary std::pair contains the copy of a. At the end of the expression the pair is destroyed, which also destroys its elements including the copy of a.
Why does temporary copy of a get destructed right after the statement? Isn't using a const reference can extend a temporary's lifetime? I mean, I think the it should not get destructed till main finishes.
The temporary here is the result of std::make_pair which is being used as an argument to the member function insert. The relevant rules that apply here are :
Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference, with the following exceptions:
[...]
a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call [...]
[...]
source
The full expression containing the function call is the expression myMap.insert(make_pair(1, a)); This means that the lifetime of the result of std::make_pair ends after the function return, including the A it contains. The new std::map element will refer to the A in the temporary std::pair which will become dangling once insert returns.
Is my boss's code incorrect and very dangerous?
Yes, myMap contains a dangling references.

What happens when I "re-initialize" a pointer

I am currently writing a piece of code in c++ and I came across some behaviour that I don't understand. Let's say that I have a custom class(I'm not sure if it matters what goes on inside the class) and I want to make a pointer to this class:
AliAODEvent* aod;
Now, after I have made this pointer, I want to assign it to a memory location. In the framework that I am using, the object that I want to point to already exists somewhere, so what I did was
AliAODEvent* aod = (This is where the object I want to point to goes);
I realize now that I should just use aod=(Object to point to); But I am curious as to what happened when I tried to essentially "re-initialize" the pointer. Any thoughts?
In C++ you have declaration and initialisation.
int x; // Declaration
x = 10; // Initialisation
Declaring a variable means asking the operating system to allocate a place in memory for it. Initialising a variable means setting the value at that memory address for the first time. You can do both at once:
int x = 10; // Declares x, then initialises it to 10
In C++ it is not allowed to declare a variable more than once:
int x; // Declares x
int x; // Tries to declare another variable also called x, fails (ERROR)
However, you CAN declare two variables with the same name as long as they are in different scopes:
#include <iostream>
int x = 10;
int main()
{
int x = 20;
{
int x = 30;
std::cout << x << ", " << ::x << std::endl; // Prints '30, 10'
}
std::cout << x << ", " << ::x << std::endl; // Prints '20, 10'
return 0;
}
{} denotes new scope, and :: denotes global scope. So you can specify global scope, or you can use local scope, but you can't use anything else with the same name.
In C++, the statement
AliAODEvent* aod = (This is where the object I want to point to goes);
means "please create for me a new variable called aod of type AliAODEvent* and assign it a particular variable." On the other hand, the statement
aod = (This is where the object I want to point to goes);
means "find an existing variable called aod and assign it to point to a new location." The distinction here is that, by including the name of the type, C++ thinks you're giving a declaration that introduces a new variable, rather than an assignment statement that takes an existing variable and changes where it points. This is just how the language is designed.
The reason this second one works while the first doesn't is that you're ultimately trying to take something that exists and change it, which means you should not be providing a declaration. Generally speaking, you only should include the type of a variable in a statement if you're declaring that variable and otherwise should just use its name.
You are not reinitializing the pointer in that case, but trying to create a pointer of the same name, which would be an error, unless it was in a different scope block.
ie:
AliAODEvent* aod;
{
AliAODEvent* aod = (something)
}
In that case, the aod variable would be ok (although might show a warning) as would be a different vaiable, which would no longer be there once the scope of it (the '}') ended.
The following code:
A* aod = &x;
A* aod = &y;
is declaring two variables, and is ill-formed. It should be rejected by most compilers but with the right settings some compilers may let it through.
What happened here is that the compiler created storage for the first variable and stored the address of x into it. Then it created additional storage for a second variable and hid the original variable.
At this point, the program is storing both the value of x and y in different memory locations, but you can only refer to the second aod until it goes out of scope.
This is usually called "shadowing" and is legal only between scopes:
#include <iostream>
struct A {};
A a, b, c;
A* ptr = &a;
void report(A* p) {
std::cout << (void*) &a << ", " << (void*) &b << ", " << (void*) &c
<< ": " << (void*) p << "\n";
}
int f() {
std::cout << "f() ";
report(ptr);
}
int main() {
report(ptr);
if (ptr != nullptr) {
A* ptr = &b;
report(ptr);
if (ptr != nullptr) {
A* ptr = &c;
f();
report(ptr);
}
report(ptr);
}
report(ptr);
}
Live demo: http://ideone.com/LBFWFT
Also, be aware that pointers are not smart.
A* aod = new A;
aod = new A;
This allocates two As but never frees the first one, because we never tell it to, we simply overwrite the value. The compiler does not keep a track of when a dynamic object is no-longer referenced.
int main() {
A* aod = nullptr;
if (aod == nullptr) { // start new scope
A x;
aod = &x;
} // end scope, `x` is destroyed.
use(aod);
}
This code introduces a bug: aod points to the address of x, but x is destroyed when it goes out of scope at the } so this pointer is dangling and references invalid memory.
In giving the pointer an address to an existing location, you don't want to use the type specifier to the left of it again, since that variable already exists (that's declaring a variable). You won't be able to declare a new variable aod again while you are in the scope of the first aod.
Additionally, to be clear, saying aod=(Object to point to); is only correct if you have the address of the object after the assignment operator, not the object itself. You assign the address of an object to a pointer by using the & operator before the name of another object to obtain its address:
Object* objectPointer = &existingObject; //point objectPointer to the address of existingObject
Or, by a method,
Object* objectPointer = method()
where method() has a return type of Object* (pointer to an Object type).
You can also create a new object on the heap using the new operator:
Object* objectPointer = new Object("args");
which must be deleted with the delete operator when you're done with it.
delete objectPointer;
Remember that just because a pointer falls out of scope and stops existing, doesn't mean that the memory it points to does.

How to avoid "unable to read memory"

I have a struct:
struct a {
a(){};
a(int one,int two): a(one),b(two){};
int a;
int b;
int c;
}
a * b;
cout << b->c;
And sometimes when i want to read (for ex.) c and in debbuger this value is called
'unable to read memory'
Then my program crashed.
And now, how to check that value is readable or not ?
Best Regards.
You haven't initialised the pointer to point to anything, so it's invalid. You can't, in general, test whether a pointer points to a valid object. It's up to you to make sure it does; for example:
a obj(1,2); // an object
a * b = &obj; // a pointer, pointing to obj;
cout << b->a; // OK: b points to a valid object
You can make a pointer null if you don't want it to point to anything. You mustn't dereference it, but it is possible to test for a null pointer:
a * b = nullptr; // or 0, in ancient dialects
if (b) cout << b->a; // OK: test prevents dereferencing
cout << b->a; // ERROR: b is null
But beware that this doesn't help in situations where a pointer might be invalid but not null; perhaps because it wasn't initialised, or because it pointed to an object that has been destroyed.
In general, avoid pointers except when you actually need them; and be careful not to use invalid pointers when you do. If you just want an object, then just use an object:
a b(1,2); // an object
cout << b.a; // OK: b is a valid object

Returning a reference - why my code works properly? It shouldn't

I've got a few doubts about references in C++.
Test & returnref(){
Test obj(9,9);
cout << "in function: " << &obj << endl;
return obj;
} // *
int main(){
Test & asdf = returnref();
Test asdf2 = returnref();
cout << "in main asdf: " << &asdf;
cout << "in main asdf2: " << &asdf2;
cin.get();
return 0;
}
the result:
in function: 0033F854
in function: 0033F854
in main asdf: 0033F854
in main asdf2: 0033F938
is it correct?
in my opinion the obj is being removed on 5th line (*) - because it's alive in this function scope.
so why it's working? Is it just Visual Studio? or maybe I'm wrong?
You are allocating an object on the function's stack and when the function returns,
The object used is destroyed. allocate it dynamically using new(followed by a delete of course),and than
do whatever you need.
Your options are to return by value or to return a reference/pointer to a heap-based object.
Return by value
Changing your function signature to this
Test returnval()
will copy obj. Note that the pointers you print out may still have the same value for the object inside the class and the object outside, as the compiler may have performed a return value optimisation.
If the Test class is not managing dynamically allocated resources, then you can rely on the automatically created copy constructors that the compiler will inject. If Test has dynamically allocated data, then you must write your own. See What is the Rule of Three?.
Return a pointer (or reference) to a heap-based object
You can change it to a heap-based object by using new, and then return a pointer instead:
Test* returnptr(){
Test* obj = new Test(9,9);
cout << "in function: " << obj << endl;
return obj;
}
Or better yet, a smart pointer like shared_ptr to manage the deletion for you:
shared_ptr<Test> returnptr() {
// Wrapping the pointer in a shared_ptr will ensure it gets cleaned
// up automatically when the last reference to it (usage of it)
// goes out of scope.
shared_ptr<Test> obj(new Test(9,9));
cout << "in function: " << obj.get() << endl;
return obj;
}
Final note
As pointed out by one of the commenters on my answer, in C++11, you have further options to control how the temporary object from your function is returned by providing move constructors for Test and using std::move as necessary. This is a fairly meaty subject, but you can read more about it at the following links:
What is move semantics?
Rvalue References: C++0x Features in VC10
A Brief Introduction to Rvalue References
Using a reference to a local variable returned by a function has undefined behavior. But note that ub doesn't mean "it will crash", means "I don't know what will happen".
In your case, your calls don't reuse the memory used by that stackframe, so your local variable is still there.

Added benefit of a pointer, when to use one and why

I'm learning C++ at the moment and though I grasp the concept of pointers and references for the better part, some things are unclear.
Say I have the following code (assume Rectangle is valid, the actual code is not important):
#include <iostream>
#include "Rectangle.h"
void changestuff(Rectangle& rec);
int main()
{
Rectangle rect;
rect.set_x(50);
rect.set_y(75);
std::cout << "x,y: " << rect.get_x() << rect.get_y() << sizeof(rect) << std::endl;
changestuff(rect);
std::cout << "x,y: " << rect.get_x() << rect.get_y() << std::endl;
Rectangle* rectTwo = new Rectangle();
rectTwo->set_x(15);
rectTwo->set_y(30);
std::cout << "x,y: " << rect.get_x() << rect.get_y() << std::endl;
changestuff(*rectTwo);
std::cout << "x,y: " << rect.get_x() << rect.get_y() << std::endl;
std::cout << rectTwo << std::endl;
}
void changestuff(Rectangle& rec)
{
rec.set_x(10);
rec.set_y(11);
}
Now, the actual Rectangle object isn't passed, merely a reference to it; it's address.
Why should I use the 2nd method over the first one? Why can't I pass rectTwo to changestuff, but *rectTwo? In what way does rectTwo differ from rect?
There really isn't any reason you can't. In C, you only had pointers. C++ introduces references and it is usually the preferred way in C++ is to pass by reference. It produces cleaner code that is syntactically simpler.
Let's take your code and add a new function to it:
#include <iostream>
#include "Rectangle.h"
void changestuff(Rectangle& rec);
void changestuffbyPtr(Rectangle* rec);
int main()
{
Rectangle rect;
rect.set_x(50);
rect.set_y(75);
std::cout << "x,y: " << rect.get_x() << rect.get_y() << sizeof(rect) << std::endl;
changestuff(rect);
std::cout << "x,y: " << rect.get_x() << rect.get_y() << std::endl;
changestuffbyPtr(&rect);
std::cout << "x,y: " << rect.get_x() << rect.get_y() << std::endl;
Rectangle* rectTwo = new Rectangle();
rectTwo->set_x(15);
rectTwo->set_y(30);
std::cout << "x,y: " << rectTwo->get_x() << rectTwo->get_y() << std::endl;
changestuff(*rectTwo);
std::cout << "x,y: " << rectTwo->get_x() << rectTwo->get_y() << std::endl;
changestuffbyPtr(rectTwo);
std::cout << "x,y: " << rectTwo->get_x() << rectTwo->get_y() << std::endl;
std::cout << rectTwo << std::endl;
}
void changestuff(Rectangle& rec)
{
rec.set_x(10);
rec.set_y(11);
}
void changestuffbyPtr(Rectangle* rec)
{
rec->set_x(10);
rec->set_y(11);
}
Difference between using the stack and heap:
#include <iostream>
#include "Rectangle.h"
Rectangle* createARect1();
Rectangle* createARect2();
int main()
{
// this is being created on the stack which because it is being created in main,
// belongs to the stack for main. This object will be automatically destroyed
// when main exits, because the stack that main uses will be destroyed.
Rectangle rect;
// rectTwo is being created on the heap. The memory here will *not* be released
// after main exits (well technically it will be by the operating system)
Rectangle* rectTwo = new Rectangle();
// this is going to create a memory leak unless we explicitly call delete on r1.
Rectangle* r1 = createARectangle();
// this should cause a compiler warning:
Rectangle* r2 = createARectangle();
}
Rectangle* createARect1()
{
// this will be creating a memory leak unless we remember to explicitly delete it:
Rectangle* r = new Rectangl;
return r;
}
Rectangle* createARect2()
{
// this is not allowed, since when the function returns the rect will no longer
// exist since its stack was destroyed after the function returns:
Rectangle r;
return &r;
}
It should also be worth mentioning that a huge difference between pointers and references is that you can not create a reference that is uninitialized. So this perfectly legal:
int *b;
while this is not:
int& b;
A reference has to refer to something. This makes references basically unusable for polymorphic situations, in which you may not know what the pointer is initialized to. For instance:
// let's assume A is some interface:
class A
{
public:
void doSomething() = 0;
}
class B : public A
{
public:
void doSomething() {}
}
class C : public A
{
public:
void doSomething() {}
}
int main()
{
// since A contains a pure virtual function, we can't instantiate it. But we can
// instantiate B and C
B* b = new B;
C* c = new C;
// or
A* ab = new B;
A* ac = new C;
// but what if we didn't know at compile time which one to create? B or C?
// we have to use pointers here, since a reference can't point to null or
// be uninitialized
A* a1 = 0;
if (decideWhatToCreate() == CREATE_B)
a1 = new B;
else
a1 = new C;
}
In C++, objects can be allocated on the heap or on the stack. The stack is valid only locally, that is when you leave the current function, the stack and all contents will be destroyed.
On the contrary, heap-objects (which must be specifically allocated using new) will live as long you don't delete them.
Now the idea is that you a caller should not need to know what a method does (encapsulation), internally. Since the method might actually store and keep the reference you have passed to it, this might be dangerous: If the calling method returns, stack-objects will be destroyed, but the references are kept.
In your simple example, it all doesn't matter too much because the program will end when main() exits anyhow. However, for every program that is just a little more complex, this can lead to serious trouble.
You need to understand that references are NOT pointers. They ,may be implemented using them (or they may not) but a reference in C++ is a completely different beast to a pointer.
That being said, any function that takes a reference can be used with pointers simply by dereferencing them (and vice versa). Given:
class A {};
void f1( A & a ) {} // parameter is reference
void f2( A * a ) {} // parameter is pointer
you can say:
A a;
f1( a )
f2 ( &a );
and:
A * p = new A;
f1( *a )
f2 ( a );
Which should you use when? Well that comes down to experience, but general good practice is:
prefer to allocate objects automatically on the stack rather than using new whenever possible
pass objects using references (preferably const references) whenever possible
rectTwo differs from rect in that rect is an instance of a Rectangle on the stack and rectTwo is the address of a Rectangle on the heap. If you pass a Rectangle by value, a copy of it is made, and you will not be able to make any changes that exist outside of the scope of changestuff().
Passing it by reference means that changestuff will have the memory address of the Rectangle instance itself, and changes are not limited to the scope of changestuff (because neither is the Rectangle).
Edit: your comment made the question more clear. Generally, a reference is safer than a pointer.
From Wikipedia:
It is not possible to refer directly to a reference object after it is
defined; any occurrence of its name
refers directly to the object it
references.
Once a reference is created, it cannot be later made to reference
another object; it cannot be reseated.
This is often done with pointers.
References cannot be null, whereas pointers can; every reference refers
to some object, although it may or may
not be valid.
References cannot be uninitialized. Because it is impossible to
reinitialize a reference, they must be
initialized as soon as they are
created. In particular, local and
global variables must be initialized
where they are defined, and references
which are data members of class
instances must be initialized in the
initializer list of the class's
constructor.
Additionally, objects allocated on the heap can lead to memory leaks, whereas objects allocated on the stack will not.
So, use pointers when they are necessary, and references otherwise.
Quite a few application domains require the use of pointers. Pointers are needed when you have intimate knowledge about how your memory is layed out. This knowledge could be because you intended the memory to be layed out in a certain way, or because the layout is out of your control. When this is the case you need pointers.
Why would you have manually structured the memory for a certain problem domain ? Well an optimal memory layout for a certain problems are orders of magnitude faster than if you used traditional techniques.
Example domains:
Enterprise Databases.
Kernel design.
Drivers.
General purpose Linear Algebra.
Binary Data serialization.
Slab Memory allocators for transaction processing (web-servers).
Video game engines.
Embedded real-time programming.
Image processing
Unicode Utility functions.
You are right to say that the actual Rectangle object isn't passed, merely a reference to it. In fact you can never 'pass' any object or anything else really. You can only 'pass' a copy of something as a parameter to a function.
The something that you can pass could be a copy of a value, like an int, or a copy of an object, or a copy of a pointer or reference. So, in my mind, passing a copy of either a pointer or a reference is logically the same thing - syntactically its different, hence the parameter being either rect or *rectTwo.
References in C++ are a distinct advantage over C, since it allows the programmer to declare and define operators that look syntactically identical to those that are available for integers.
eg. the form: a=b+c can be used for ints or Rectangles.
This is why you can have changestuff(rect); because the parameter is a reference and a reference to (pointer to) rect is taken automatically. When you have the pointer Rectangle* rectTwo; it is an 'object' in its own right and you can operate on it, eg reassign it or increment it. C++ has chosen to not convert this to a reference to an object, you have to do this manually by 'dereferencing' the pointer to get to the object, which is then automatically converted to a reference. This is what *rectTwo means: dereferencing a pointer.
So, rectTwo is a pointer to a Rectangle, but rect is a rectangle, or a reference to a Rectangle.