A.connected_to[0] = &B;
Does copy something: the temporary pointer value of the expression &B
.
The vector template class will always do automatic copy construction and destruction, but copy construction of a primitive type is equivalent to assignment and destruction of a primitive type, including pointers, is a no-op.
A pointer is a very basic type - almost nothing is automatically done for you when using pointers. Under the hood it's just an integral value corresponding to an address in memory. When you dereference a pointer, the compiler simply trusts you that the pointer hold the address of (or "points at") an object of the correct type.
For example, given classes Foo and Bar which are not related by inheritance:
Foo *ptr1, *ptr2;
Bar *ptr3;
// All pointers are uninitialized.
// Dereferencing them is undefined behavior. Most likely a crash.
// The compiler will almost certainly issue a warning.
ptr1= new Foo(); // ptr1 now points to a valid Foo.
ptr2 = ptr1; // ptr2 points to the same Foo.
ptr3=(Bar*)ptr1; // This is an obvious programmer error which I am making here for demonstration.
// ptr3 points to the same block of memory as ptr1 & 2.
// Dereferencing it is likely to do strange things.
delete ptr1; // The compiler is allowed to set ptr1 to 0, but you can't rely on it.
// In either case dereferencing ptr1 is once again undefined behavior
// and the value of ptr2 is unchanged.
The compiler is much less likely to issue a warning if it sees ptr1
dereferenced after deletion than before initialization. It will virtually never issue a warning if you dereference ptr2
after deleting the object through ptr1
. If you are not careful as others have warned you, your vector of pointers may lead you to inadvertently invoke undefined behavior in this way.
I introduced the extremely wrong cast of a Foo*
to a Bar*
to illustrate the compiler's absolute trust in you. The compiler allows you to do it and will happily treat the bits as if they were a Bar when you dereference ptr3
.
The C++ standard library provides few template classes that offer pointer-like behavior with much more automatic safety. For example, the std::shared_pointer
:
std::shared_ptr
is a smart pointer that manages lifetime of an object,
typically allocated with new
. Several shared_ptr
objects may manage
the same object; the object is destroyed when the last remaining
shared_ptr
pointing to it is destroyed or reset. The object is
destroyed using delete-expression or a custom deleter that is supplied
to shared_ptr
during construction.
If your environment does not yet provide the c++11 standard library, it might provide either the boost library or the std::tr1::
namespace. Both provide a very similar shared_ptr
. std::auto_ptr
, which you are sure to have, is similar but allows only one auto_ptr
to refer to an object at a given time. (C++11 introduces std::unique_ptr
as an intended replacement for auto_ptr
. The auto_ptr
is incompatible with most std template containers. unique_ptr
can be placed in a template container with std::move
.)
It is possible to break either of these classes by keeping or obtaining the pointer and monkeying around with it, e.g.
Foo *basic_ptr=new Foo();
std::auto_ptr<Foo> fancy_ptr(basic_ptr);
delete basic_ptr; // Oops! This statement broke our auto_ptr.
You will also break them if you pass in an address of a variable in automatic storage:
Foo aFoo;
std::auto_ptr<Foo> fancy_ptr(&aFoo); // automatic storage automatically breaks auto_ptr
If you just do std::shared_ptr<sn> fresh_sn(new sn())
and then use a std::vector< std::shared_ptr<sn> >
you'll be fine.