Оператор размещения new *
Существует третья форма оператора new, которая создает объект без отведения для него памяти, то есть в памяти, которая уже была выделена. Эту форму называют оператором размещения new. Программист указывает адрес области памяти, в которой размещается объект:
new (place_address) type-specifier
place_address должен быть указателем. Такая форма (она включается заголовочным файлом <new>) позволяет программисту предварительно выделить большую область памяти, которая впоследствии будет содержать различные объекты. Например:
#include <iostream>
#include <new>
const int chunk = 16;
class Foo {
public:
int val() { return _val; }
FooQ(){ _val = 0; }
private:
int _val;
};
// выделяем память, но не создаем объектов Foo
char *buf = new char[ sizeof(Foo) * chunk ];
int main() {
// создаем объект Foo в buf
Foo *pb = new (buf) Foo;
// проверим, что объект помещен в buf
if ( pb.val() == 0 )
cout << "Оператор new сработал!" << endl;
// здесь нельзя использовать pb
delete[] buf;
return 0;
}
Результат работы программы:
Оператор new сработал!
Для оператора размещения new нет парного оператора delete: он не нужен, поскольку эта форма не выделяет память. В предыдущем примере необходимо освободить память, адресуемую указателем buf, а не pb. Это происходит в конце программы, когда буфер больше не нужен. Поскольку buf ссылается на символьный массив, оператор delete имеет форму
delete[] buf;
При уничтожении buf прекращают существование все объекты, созданные в нем. В нашем примере pb больше не ссылается на существующий объект класса Foo.
Упражнение 8.5
Объясните, почему приведенные операторы new ошибочны:
(a) const float *pf = new const float[100];
(b) double *pd = new doub1e[10] [getDim()];
(c) int (*pia2)[ 1024 ] = new int[ ][ 1024 ];
(d) const int *pci = new const int;
Упражнение 8.6
Как бы вы уничтожили pa?
typedef int arr[10];
int *pa = new arr;
Упражнение 8.7
Какие из следующих операторов delete содержат потенциальные ошибки времени выполнения и почему:
int globalObj;
char buf[1000];
void f() {
int *pi = &global0bj;
double *pd = 0;
float *pf = new float(O);
int *pa = new(buf)int[20];
delete pi; // (a)
delete pd; // (b)
delete pf; // (c)
de1ete[] pa; // (d)
}
Упражнение 8.8
Какие из данных объявлений auto_ptr неверны или грозят ошибками времени выполнения? Объясните каждый случай.
int ix = 1024;
int *pi = & ix;
int *pi2 = new int ( 2048 );
(a) auto_ptr<int> p0(ix);
(b) auto_ptr<int> pl(pi);
(c) auto_ptr<int> p2(pi2);
(d) auto_ptr<int> p3(&ix);
(e) auto_ptr<int> p4(new int(2048));
(f) auto_ptr<int> p5(p2.get());
(9) auto_ptr<int> p6(p2.release());
(h) auto_ptr<int> p7(p2);
Упражнение 8.9
Объясните разницу между следующими инструкциями:
int *pi0 = p2.get();
int *pi1 = p2.release() ;
Для каких случаев более приемлем тот или иной вызов?
Упражнение 8.10
Пусть мы имеем:
auto_ptr< string > ps( new string( "Daniel" ) );
В чем разница между этими двумя вызовами assign()?Какой их них предпочтительнее и почему?
ps.get()->assign( "Danny" );
ps->assign( "Danny" );