Вызов метода в конструкторе - PullRequest
20 голосов
/ 02 февраля 2011

Херб Саттер упоминает в одной из своих http://www.gotw.ca статей о том, что объект создан (имеет допустимое существование) только в том случае, если конструктор выполнит завершение. То есть, грубо говоря, управление переходит за окончательную скобку. 1003 *

Теперь рассмотрим следующий код

class A
{
  public:
  A() 
  { 
      f();
  }

  void f() 
  { 
      cout << "hello, world"; 
  }

}; 

int main()
{
   A a;
}

Теперь из того, что говорит Херб, мы не можем сказать, что, поскольку A не полностью сконструирован внутри своего конструктора. Вызов f () внутри конструктора недопустим, поскольку ptr "this" еще не готов.

Тем не менее, внутри конструктора действительно есть допустимое "this", и f () действительно вызывается.

Я не думаю, что Херб говорит что-то неправильное ... но думаю, что я неверно истолковываю это ... некоторые могут объяснить мне, что именно это такое?

Вот ссылка на статью: http://www.gotw.ca/gotw/066.htm Это говорит об исключениях из конструкторов. В частности, вот выдержка из него, на которой основан мой вопрос:

-Когда начинается жизнь объекта? Когда его конструктор завершается успешно и возвращает нормально . Таким образом, элемент управления достигает конца тела конструктора или более раннего оператора возврата.

-Когда заканчивается срок службы объекта? Когда начинается его деструктор. То есть контроль достигает начала тела деструктора. Важным моментом здесь является то, что состояние объекта до того, как начинается его время жизни, точно такое же, как и после того, как заканчивается его время жизни - объекта нет, период . Это наблюдение подводит нас к ключевому вопросу:

Мы можем обобщить модель конструктора C ++ следующим образом:

Either:

(a) The constructor returns normally by reaching its end or a return statement, and the object exists.

Or:

(b) The constructor exits by emitting an exception, and the object not only does not now exist, but never existed.

Ответы [ 5 ]

18 голосов
/ 02 февраля 2011

Теперь из того, что говорит Херб, мы не можем сказать что, поскольку А не полностью построен внутри своего конструктора Вызов f () внутри конструктора недействителен, так как «этот» ptr не готов еще.

Это только тогда, когда f() является virtual методом class A или его иерархией наследования, и вы ожидаете разрешение во время выполнения для f() в соответствии с нужным объектом. Проще говоря, механизм virtual не срабатывает, если метод вызывается внутри конструктора.

Если f() не является виртуальной функцией, то вызывать ее из конструктора (-ов) не повредит, если вы знаете, что именно f() делает. Программисты обычно вызывают методы класса, такие как initialize() из конструктора (ов).

Можете ли вы дать мне ссылку на статью Херба Саттера?

8 голосов
/ 02 февраля 2011

К тому времени, когда программный поток входит в ваш конструктор, память объекта уже выделена, и указатель this действительно действителен.

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

Это важно, если у вас есть виртуальные функции-члены, поскольку любая виртуальная функция в производном классе не будет запускаться, если она вызывается из конструктора А.

3 голосов
/ 02 февраля 2011

Примечание: с точной статьей было бы проще, чтобы у нас был некоторый контекст

Пожизненные соображения на самом деле довольно сложны.

Учитывая конструктор объекта, существуют две разные точки зрения:

  • внешний: т.е. пользователь объекта
  • внутренний: то есть вы при написании конструкторов и деструкторов (особенно)

С внешней точки зрения время жизни объекта:

  • начинается после успешного завершения конструктора
  • заканчивается, когда деструктор начинает работать

Это означает, что если вы пытаетесь получить доступ к объекту в середине строительства или в середине разрушения Плохие вещи случаются (tm) . Это в основном относится к многопоточным программам, но может произойти, если вы передадите указатели на ваш объект базовым классам ... что приводит к ...

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

  • в теле конструктора вы можете использовать атрибуты и базы класса (они инициализируются) и вызывать функции нормально (виртуальных вызовов следует избегать).
  • если это базовый класс, производный объект еще не инициализирован (таким образом, ограничение на виртуальные вызовы)
2 голосов
/ 02 февраля 2011

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

0 голосов
/ 02 февраля 2011

Остерегайтесь переменных-членов, которые еще не инициализированы. Остерегайтесь виртуальных функций: функция, которую вы вызываете, может не соответствовать ожидаемой, если функция является виртуальной и создается производный объект. Кроме этого, я не вижу проблем с вызовом методов из конструктора. Тем более память для объекта уже выделена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...