«Точка создания» автоматической переменной - PullRequest
4 голосов
/ 16 февраля 2012
void foo()  
{  
    //some code

    MyClass m();

    //some more code
}

Обеспечивает ли стандарт C ++, что конструктор класса MyClass будет вызываться после запуска //some code, или это неуказанное поведение?

Ответы [ 5 ]

4 голосов
/ 16 февраля 2012

Технический ответ на этот вопрос заключается в том, что компилятор гарантирует, что конструктор вообще не запускается, потому что строка

MyClass m();

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

MyClass m;

Поскольку это такой источник путаницы, в C ++ 11 есть новый синтаксис, который вы можете использовать для инициализации автоматических объектов.Вместо использования скобок используйте фигурные скобки, например:

MyClass m{};

Это говорит компилятору использовать нулевой конструктор для MyClass, как и предполагалось, так как нет способа интерпретировать вышеприведенное как прототип функции.

Если вы сделаете это изменение, компилятор гарантирует, что конструктор m будет выполнен после первого фрагмента кода и перед вторым фрагментом кода.

Надеюсь, это поможет!

3 голосов
/ 16 февраля 2012

Прежде всего MyClass m(); не создает никаких объектов, вы, вероятно, имели в виду MyClass m;. Да, гарантируется, что объект создается только после запуска //some code.

1 голос
/ 16 февраля 2012

Здесь не создается никакого объекта.

MyClass m();

Объявляет функцию с именем m, которая не принимает аргументов и возвращает объект типа MyClass.

MyClass m

создаст объект с именем m типа MyClass, и да, гарантируется, что конструктор для m будет вызываться только при выполнении этой строки кода.

0 голосов
/ 16 февраля 2012

Предположим, что вы хотели объявить переменную, как уже отмечалось:

void foo() {
  // {before}
  MyClass m;
  // {after}
}

Затем семантически , конструктор выполняется после {before} и до {после} .

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

Наблюдаемые эффекты, в частности, включают:

  • модификация volatile переменных
  • системных вызовов (включая операции с памятью)

По умолчанию функцияопределение которого неизвестно, как предполагается, имеет наблюдаемые эффекты.

Заметным исключением является оптимизация Copy Elision , которую Стандарт допускает в ряде случаев, даже если конструктор копирования может иметь наблюдаемые эффекты.

Конкретно, это означает, что с учетом:

int before();
int after();

void foo() {
  int n = 5;
  int const a = before();
  n += a;

  MyClass m;

  int const c = after();
  n += c;

  std::cout << n << "\n";
}

Стандарт гарантирует следующий порядок:

  • before();
  • MyClass m;
  • after();
  • std::cout << n << "\n";

Однако не гарантируется, как вычисляется n.Все, что известно, это то, что в момент его печати оно будет равно 5 + a + c, но не имеет значения, задерживается ли вычисление непосредственно перед печатью или выполняется с нетерпением каждый раз, когда появляется новый элемент:не изменяет наблюдаемое поведение.

Следовательно, две следующие версии foo эквивалентны:

void foo_eager() {
  int n = 5;
  n += before();
  MyClass m;
  n += after();
  std::cout << n << "\n";
}

void foo_lazy() {
  int const a = before();
  MyClass m;
  int const c = after();
  std::cout << (5 + a + c) << "\n";
}
0 голосов
/ 16 февраля 2012

MyClass m(); -> Здесь не создается никаких объектов.Это просто объявление функции, которая не принимает параметров, но возвращает объект MyClass.

Если вам нужно создать объект, просто напишите MyClass m; или MyClass *m = new MyClass(); Да, конструктор MyClass вызывается после некоторого кода.

...