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.
Related
I am struggling to understand the difference in behaviour of a raw pointer and a unique_ptr. I have class A with a variable x and class B with a pointer to an instance of A:
class A
{
public:
int x;
};
A::A(int y) : x(y)
{
}
class B
{
public:
B(A &);
A *p;
};
B::B(A &a)
{
p = &a;
}
This behaves as I would expect:
int main()
{
A a(2);
B b(a);
cout << a.x << " " << b.p->x << endl;
a.x = 4;
cout << a.x << " " << b.p->x << endl;
}
gives
2 2
4 4
Changing the raw pointer to a std::unique_ptr gives a different result:
class A
{
public:
int x;
};
A::A(int y) : x(y)
{
}
class B
{
public:
B(A &);
std::unique_ptr<A> p;
};
B::B(A &a)
{
p = std::make_unique<A>(a);
}
gives
2 2
4 2
Have I fundamentally misunderstood something about unique_ptrs?
make_unique creates a fresh object, one that that unique_pt has exclusive access to. So in the second example you have two objects, not one and when you set change the value of a.x in the first object it doesn't effect the other object held by the unique_ptr.
A unique pointer needs to own whatever it points to. Your code can be made to work - just substituting unique_ptr type and leaving everything else unchanged (no make_unique). But it will have undefined behavior, since you’ll create a unique pointer to an object that is owned elsewhere.
To compare apples to apples, the raw pointer code should read p=new A(a);. That’s what make_unique does.
Try reading the following expression from the smart pointer version:
std::make_unique<A>(a);
"make a unique A from a" (no mention of pointers!)
The result is a unique_ptr, but when reading the expression, read it as making (an object whose type is) the template parameter. The function parameters are parameters to the constructor. In this case, you are making an A object from an A object, which pulls in the copy constructor.
Once you understand that the smart pointer version is making a new A object (and your raw pointer version does not), your results should make sense.
The "unique" in "unique A" might be tricky to understand. Think of it as an object that no one else can lay claim to. It might be a copy of another object, but, taking the role of the unique_ptr, it is your copy, your responsibility to clean up after, and no one else's. Your preciousss, which you will not share (c.f. std::make_shared).
Note that a local variable (like the a in the main function) is the responsibility of the compiler, so it is ineligible to be the object to which a unique_ptr points (or any smart pointer, for that matter).
If I have a unique pointer and I create an alias for it in a function, and that alias goes out of scope, why doesn't the original unique_ptr also get destroyed? After all, 'b' as defined in the function below is basically the same object in memory as 'x'. What is going on behind the scenes?
#include <iostream>
#include <memory>
void testfunc(std::unique_ptr<int>& x) {
std::unique_ptr<int>& b = x;
}
int main() {
std::unique_ptr<int> a(new int(5));
std::cout << *a << std::endl; // 5
testfunc(a);
std::cout << *a << std::endl; // 5
}
What you're using is a reference, and a reference in C++ is a distinct type from what it is referencing. You can interact with an object through a reference, but the reference itself and the object being referred to have separate lifetimes. When one is destroyed, the other doesn't automatically get destroyed. This means you can pass a reference into a function and then at the end of a function when the reference is destroyed the original object is still valid. This allows passing around large complex objects without needing to copy or even moving them. It's a implementation detail, but it's common for compilers to simply use a pointer "behind the scenes" as references.
As a side note, this aspect of references in C++ leads to the infamous dangling reference issue. If you hold a reference to some object and that object is destroyed the reference you have is now technically invalid, and you'll invoke undefined behavior if you use it. Unfortunately there is nothing built into the language to automatically detect or deal with this situation. You must architect your program to avoid it.
A reference is can be considered like an alias to an element, hence it references another variable by taking up its value and working just like it does, but it doesn't get destroyed until called by the destructor or forcibly destroyed by the programmer which will also destroy the variable it references... since a reference is just an editable alias... However their lifespan differs since a non-reference type can be moved and it becomes out of scope...
"What is going on behind the scenes?"
Inside the memory, the reference allows us to change the value of an element and if often used instead of pointers which were a common practice in C... But, its value cannot be moved unless passed... A reference's value won't change unless changed using an assignment operation directly or indirectly i.e, from the function parameter x which itself is an alias...
Like: x = std::make_unique<int>(6); will change the value of a to 6 instead... But what you have done here instead is...
auto& b = x;
Nothing actually happens except the value that x(references to a) is referencing to is copied and passed to b (which just acts like another alias)... So it is similar to doing: auto& b = a;, but since a is outside the scope, it references a's value indirectly...
#include <iostream>
#include <memory>
void testfunc(std::unique_ptr<int>& x)
{
auto& b(x); // 'b' is an alias of 'x' and 'x' is an alias of 'a'
b = std::make_unique<int>(6); // Setting 'b' to 6 meaning setting 'a' to 6...
/* Now you can't do 'x = b' since you cannot assign a value to an alias and it is
like a 'circular assignment operation'...*/
}
int main()
{
std::unique_ptr<int> a(new int(5));
std::cout << *a << std::endl; // 5 : Nothing happens, just initialization...
testfunc(a); // It does not affect the reference...
std::cout << *a << std::endl; /* 6 : Since reference is an 'alias', you
changed 'a' as well...*/
} // It is freed after use by the destructor...
So, a general advice from people would be that you should avoid references if you are unsure of what it does (It can change the real variable if you are unknown of its consequences)... and take some time to learn about them...
If you destroy the original however..., all the references themselves will become invalidated... In such a case, when trying to access the value of destroyed (nullified) object is undefined causing undefined behavior...
#include <iostream>
#include <memory>
void testfunc(std::unique_ptr<int>& x) { // you take a reference to a unique_ptr
std::unique_ptr<int>& b = x; // which will do nothing to the lifetime of
} // the unique_ptr you pass to the function,
// then you assign the passed parameter
// to another reference. again, that does
// nothing to the lifetime of the original.
int main() {
std::unique_ptr<int> a(new int(5));
std::cout << *a << std::endl; // 5
testfunc(a);
std::cout << *a << std::endl; // 5
}
After all, 'b' as defined in the function below is basically the same object in memory as 'x'.
Not at all. x is a reference. A reference is not an object, and no constructor or destructor is called for it. There are no "aliases" for variables. There are for types, also known as typedefs.
Consider the same code with pointers instead:
void testfunc(std::unique_ptr<int>* x) {
std::unique_ptr<int>* b = x;
}
int main() {
std::unique_ptr<int> a(new int(5));
std::cout << *a << std::endl; // 5
testfunc(&a);
std::cout << *a << std::endl; // 5
}
The only time a reference can affect the lifetime of an object is when a reference binds to a temporary, but even then, it extends the lifetime rather than reducing it:
struct A {};
int main() {
{
A(); // Constructed and destructed
}
{
A const& a = A(); // Constructed
// Other instructions
} // Destructed
}
Demo
This is a simple thing that I'm not sure if it is possible in C++ like in some other languages. The thing behaves like it is a copy, but not the same object. I would expect that if this was struct, or some other value type - this would be expected behaviour, but for class, I expected this to behave like I'm looking at "reference", that is - the same object as is in array. What am I doing wrong?
// Example program
#include <iostream>
#include <string>
class someclass
{
public:
void setn(int n2);
int n=10;
};
void someclass::setn(int n2){
n=n2;
};
int main()
{
someclass moreofthem[5];
someclass my=moreofthem[1];
std::cout << "start value: " << my.n << " as inital\n"; //10
my.setn(2);
std::cout << "new value: " << my.n << " as expected\n"; //2
std::cout << "value in list: " << moreofthem[1].n << " why?\n"; //10?
}
Unlike C#, C++ makes no distinction between a struct and a class. In fact, the two are completely interchangeable, and follow value semantic.
Fortunately, C++ also provides references and pointers as language constructs, which let you deal with references to instances of classes and structures:
someclass moreofthem[5];
someclass& my = moreofthem[1];
// ^
// That's it! Now you have yourself a reference
std::cout << "start value: " << my.n << " as inital\n"; //10
my.setn(2);
or if you prefer pointers
someclass moreofthem[5];
someclass* my = &moreofthem[1];
// ^ ^
// declare and use a pointer; note -> below
std::cout << "start value: " << my.n << " as inital\n"; //10
my->setn(2);
Unlike C#, where a class ensures that instances are handled through references (which represent a mix between C++ references and C++ pointers) C++ lets you decide how you want to handle your instances - by value, by reference, or by pointer. The behavior is close to C#'s ref parameter passing for objects of value type, but it is available in all contexts, including instance and local variables. This gives you more flexibility to handle the same object through a reference or by value in different contexts.
That's because the object my is a copy of moreofthem[1], not a reference.
If you want a reference you need to use the ampersand when defining the variable:
someclass& my=moreofthem[1];
// ^
// Note ampersand here
I would expect that if this was struct, or some other value type -
this would be expected behaviour, but for class, ...
The keywords class and struct can be used interchangeably. The only difference is that, if you don't specify an access modifer the default would
be :
public in struct
private in class
That said,
someclass& my=moreofthem[1];
makes a reference and that is what you're looking for. Here the reference my acts like an alias of the original variable moreofthem[1]
My professor in C++ has shown us this as an example in overloading the operator new (which i believe is wrong):
class test {
// code
int *a;
int n;
public:
void* operator new(size_t);
};
void* test::operator new(size_t size) {
test *p;
p=(test*)malloc(size);
cout << "Input the size of array = ?";
cin >> p->n;
p->a = new int[p->n];
return p;
}
Is this right?
It's definitely "not right", in the sense that it's giving me the creeps.
Since test has no user-declared constructors, I think it could work provided that the instance of test isn't value-initialized (which would clear the pointer). And provided that you write the corresponding operator delete.
It's clearly a silly example, though - user interaction inside an overloaded operator new? And what if an instance of test is created on the stack? Or copied? Or created with test *tp = new test(); in C++03? Or placement new? Hardly user-friendly.
It's constructors which must be used to establish class invariants (such as "I have an array to use"), because that's the only way to cover all those cases. So allocating an array like that is the kind of thing that should be done in a constructor, not in operator new. Or better yet, use a vector instead.
As far as the standard is concerned - I think that since the class is non-POD the implementation is allowed to scribble all over the data in between calling operator new and returning it to the user, so this is not guaranteed to work even when used carefully. I'm not entirely sure, though. Conceivably your professor has run it (perhaps many years ago when he first wrote the course), and if so it worked on his machine. There's no obvious reason why an implementation would want to do anything to the memory in the specific case of this class.
I believe that is "wrong" because he
access the object before the
constructor.
I think you're correct on this point too - casting the pointer returned from malloc to test* and accessing members is UB, since the class test is non-POD (because it has private non-static data members) and the memory does not contain a constructed instance of the class. Again, though, there's no reason I can immediately think of why an implementation would want to do anything that stops it working, so I'm not surprised if in practice it stores the intended value in the intended location on my machine.
Did some Standard checking. Since test has private non-static members, it is not POD. So new test default-initializes the object, and new test() value-initializes it. As others have pointed out, value-initialization sets members to zero, which could come as a surprise here.
Default-initialization uses the implicitly defined default constructor, which omits initializers for members a and n.
12.6.2p4: After the call to a constructor for class X has completed, if a member of X is neither specified in the constructor's mem-initializers, nor default-initialized, nor value-initialized, nor given a value during execution of the body of the constructor, the member has indeterminate value.
Not "the value its memory had before the constructor, which is usually indeterminate." The Standard directly says the members have indeterminate value if the constructor doesn't do anything about them.
So given test* p = new test;, p->a and p->n have indeterminate value and any rvalue use of them results in Undefined Behavior.
The creation/destruction of objects in C++ is divided into two tasks: memory allocation/deallocation and object initialization/deinitialization. Memory allocation/deallocation is done very differently depending on an object's storage class (automatic, static, dynamic), object initialization/deinitialization is done using the object's type's constructor/destructor.
You can customize object initialization/deinitialization by providing your own constructors/destructor. You can customize the allocation of dynamically allocated objects by overloading operator new and operator delete for this type. You can provide different versions of these operators for single objects and arrays (plus any number of additional overloads).
When you want to fine-tune the construction/destruction of objects of a specific type you first need to decide whether you want to fiddle with allocation/deallocation (of dynamically allocated objects) or with initialization/deinitialization. Your code mixes the two, violating one of C++' most fundamental design principle, all established praxis, every known C++ coding standard on this planet, and your fellow-workers' assumptions.
Your professor is completely misunderstanding the purpose of operator new whose only task is to allocate as much memory as was asked and to return a void* to it.
After that the constructor is called to initialize the object at that memory location. This is not up to the programmer to avoid.
As the class doesn't have a user-defined constructor, the fields are supposed to be uninitialized, and in such a case the compiler has probably freedom to initialize them to some magic value in order to help finding use of uninitialized values (e.g for debug builds). That would defeat the extra work done by the overloaded operator.
Another case where the extra work will be wasted is when using value-initialization: new test();
This is very bad code because it takes initialization code that should be part of a constructor and puts it in operator new which should only allocate new memory.
The expression new test may leak memory (that allocated by p->a = new int[p->n];) and the expression new test() definitely will leak memory. There is nothing in the standard that prevents the implementation zeroing, or setting to an alternate value, the memory returned by a custom operator new before that memory is initialized with an object even if the subsequent initialization wouldn't ordinarily touch the memory again. If the test object is value-initialized the leak is guaranteed.
There is also no easy way to correctly deallocate a test allocated with new test. There is no matching operator delete so the expression delete t; will do the wrong thing global operator delete to be called on memory allocated with malloc.
This does not work.
Your professor code will fail to initialize correctly in 3/4 of cases.
It does not initialize objects correctly (new only affects pointers).
The default constructor generated for tests has two modes.
Zero Initialization (which happens after new, but POD are set to zero)
Default Initialization (POD are uninitialized)
Running Code (comments added by hand)
$ ./a.exe
Using Test::new
Using Test::new
A Count( 0) // zero initialized: pointer leaked.
A Pointer(0)
B Count( 10) // Works as expected because of default init.
B Pointer(0xd20388)
C Count( 1628884611) // Uninitialized as new not used.
C Pointer(0x611f0108)
D Count( 0) // Zero initialized because it is global (static storage duration)
D Pointer(0)
The Code
#include <new>
#include <iostream>
#include <stdlib.h>
class test
{
// code
int *a;
int n;
public:
void* operator new(size_t);
// Added dredded getter so we can print the values. (Quick Hack).
int* getA() const { return a;}
int getN() const { return n;}
};
void* test::operator new(size_t size)
{
std::cout << "Using Test::new\n";
test *p;
p=(test*)malloc(size);
p->n = 10; // Fixed size for simple test.
p->a = new int[p->n];
return p;
}
// Objects that have static storage duration are zero initialized.
// So here 'a' and 'n' will be set to 0
test d;
int main()
{
// Here a is zero initialized. Resulting in a and n being reset to 0
// Thus you have memory leaks as the reset happens after new has completed.
test* a = new test();
// Here b is default initialized.
// So the POD values are undefined (so the results are what you prof expects).
// But the standard does not gurantee this (though it will usually work because
// of the it should work as a side effect of the 'zero cost principle`)
test* b = new test;
// Here is a normal object.
// New is not called so its members are random.
test c;
// Print out values
std::cout << "A Count( " << a->getN() << ")\n";
std::cout << "A Pointer(" << a->getA() << ")\n";
std::cout << "B Count( " << b->getN() << ")\n";
std::cout << "B Pointer(" << b->getA() << ")\n";
std::cout << "C Count( " << c.getN() << ")\n";
std::cout << "C Pointer(" << c.getA() << ")\n";
std::cout << "D Count( " << d.getN() << ")\n";
std::cout << "D Pointer(" << d.getA() << ")\n";
}
A valid example of what the professor failed to do:
class test
{
// code
int n;
int a[1]; // Notice the zero sized array.
// The new will allocate enough memory for n locations.
public:
void* operator new(size_t);
// Added dredded getter so we can print the values. (Quick Hack).
int* getA() const { return a;}
int getN() const { return n;}
};
void* test::operator new(size_t size)
{
std::cout << "Using Test::new\n";
int tmp;
std::cout << How big?\n";
std::cin >> tmp;
// This is a half arsed trick from the C days.
// It should probably still work.
// Note: This may be what the professor should have wrote (if he was using C)
// This is totally horrible and whould not be used.
// std::vector is a much:much:much better solution.
// If anybody tries to convince you that an array is faster than a vector
// The please read the linked question below where that myth is nailed into
// its over sized coffin.
test *p =(test*)malloc(size + sizeof(int) * tmp);
p->n = tmp;
// p->a = You can now overflow a upto n places.
return p;
}
Is std::vector so much slower than plain arrays?
As you show this is wrong. You can also see how easy it is to get this wrong.
There usually isn't any reason for it unless you are trying to manage your own memory allocations and in a C++ environment you would be better off learning the STL and write custom allocators.
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.