Язык программирования C++. Вводный курс



              

Почленная инициализация A - часть 2


// вызывается пять копирующих конструкторов класса string

vector< string > svec( 5 );

(В этом примере с помощью конструктора string по умолчанию создается один временный объект, который затем копируется в пять элементов вектора посредством копирующего конструктора string.)

·                  вставка объекта класса в контейнер:

svec.push_back( string( "pooh" ));

Для большинства определений реальных классов почленная инициализация по умолчанию не соответствует семантике класса. Чаще всего это случается, когда его член представляет собой указатель, который адресует освобождаемую деструктором память в хипе, как, например, в нашем Account.

В результате такой инициализации newAcct._name и oldAcct._name

указывают на одну и ту же C-строку. Если oldAcct выходит из области видимости и к нему применяется деструктор, то newAcct._name указывает на освобожденную область памяти. С другой стороны, если newAcct модифицирует строку, адресуемую _name, то она изменяется и для oldAcct. Подобные ошибки очень трудно найти.

Одно из решений псевдонимов указателей заключается в том, чтобы выделить область памяти для копии строки и инициализировать newAcct._name адресом этой области. Следовательно, почленную инициализацию по умолчанию для класса Account

нужно подавить за счет предоставления явного копирующего конструктора, который реализует правильную семантику инициализации.

Внутренняя семантика класса также может не соответствовать почленной инициализации по умолчанию. Ранее мы уже объясняли, что два разных объекта Account не должны иметь одинаковые номера счетов. Чтобы гарантировать такое поведение, мы должны подавить почленную инициализацию по умолчанию для класса Account. Вот как выглядит копирующий конструктор, решающий обе эти проблемы:

inline Account::

Account( const Account &rhs )

{

   // решить проблему псевдонима указателя

   _name = new char[ strlen(rhs._name)+1 ];

   strcpy( _name, rhs._name );

   // решить проблему уникальности номера счета

   _acct_nmbr = get_unique_acct_nmbr();

   // копирование этого члена и так работает

   _balance = rhs._balance;

<


Содержание  Назад  Вперед