A.connected_to[0] = &B;
Копирует ли что-то: значение временного указателя выражения &B
.
Класс векторного шаблона всегда будет выполнять автоматическое создание и уничтожение копии, но создание копии примитивного типа эквивалентно присвоению и уничтожению примитивного типа, включая указатели, не допускается.
Указатель - это очень простой тип - практически ничего не делается автоматически при использовании указателей. Под капотом это просто целое значение, соответствующее адресу в памяти. Когда вы разыменовываете указатель, компилятор просто доверяет вам, что указатель содержит адрес (или «указывает на») объекта правильного типа.
Например, для заданных классов Foo и Bar, которые не связаны наследованием:
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.
Компилятор с гораздо меньшей вероятностью выдаст предупреждение, если увидит, что ptr1
разыменовано после удаления, чем до инициализации. Он практически никогда не выдаст предупреждение, если вы разыменуете ptr2
после удаления объекта через ptr1
. Если вы не будете осторожны, как вас предупреждали другие, ваш вектор указателей может привести к непреднамеренному вызову неопределенного поведения таким образом.
Я ввел крайне неправильный приведение Foo*
к Bar*
, чтобы проиллюстрировать абсолютное доверие компилятора к вам. Компилятор позволяет вам сделать это и с удовольствием обработает биты, как если бы они были Bar, когда вы разыменовываете ptr3
.
Стандартная библиотека C ++ предоставляет несколько шаблонных классов, которые предлагают поведение, похожее на указатель, с гораздо большей автоматической безопасностью. Например, std::shared_pointer
:
std::shared_ptr
- это умный указатель, который управляет временем жизни объекта,
обычно выделяется с new
. Несколько shared_ptr
объектов могут управлять
тот же объект; объект уничтожается, когда последний оставшийся
shared_ptr
указание на него уничтожено или сброшено. Объект
уничтожено с помощью выражения удаления или предоставленного пользовательского удалителя
до shared_ptr
во время строительства.
Если ваша среда еще не предоставляет стандартную библиотеку c ++ 11, она может предоставить либо библиотеку boost, либо пространство имен std::tr1::
. Оба обеспечивают очень похожий shared_ptr
. std::auto_ptr
, который вы обязательно должны иметь, аналогичен, но позволяет только одному auto_ptr
ссылаться на объект в данный момент времени. (C ++ 11 вводит std::unique_ptr
в качестве замены для auto_ptr
. auto_ptr
несовместим с большинством шаблонных контейнеров std. unique_ptr
может быть помещен в контейнер шаблонов с std::move
.)
Можно сломать любой из этих классов, сохраняя или получая указатель и манипулируя им, например,
Foo *basic_ptr=new Foo();
std::auto_ptr<Foo> fancy_ptr(basic_ptr);
delete basic_ptr; // Oops! This statement broke our auto_ptr.
Вы также сломаете их, если передадите адрес переменной в автоматическом хранилище:
Foo aFoo;
std::auto_ptr<Foo> fancy_ptr(&aFoo); // automatic storage automatically breaks auto_ptr
Если вы просто сделаете std::shared_ptr<sn> fresh_sn(new sn())
, а затем используете std::vector< std::shared_ptr<sn> >
, все будет в порядке.