Как создать временный объект в С++

У меня есть следующий фрагмент кода.

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

int a;
int main() {
  A(a);  // Line 'a
  return 0;
}

Что я хочу делать в строке 'a - создать временный A с конструктором A::A(int). Я знаю, что это немедленно разрушит. Это то, что я хочу. Но похоже, что компилятор делает что-то эквивалентное A a, определяя переменную A как класс A и инициализируя ее с помощью конструктора A::A(). Конечно, этого не существует, следовательно, ошибка компилятора.

Однако, если я изменю свой код на следующий.

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

void f(A) {
}

int a;
int main() {
  f(A(a));
  return 0;
}

Теперь он отлично работает. Компилятор создает временный A и использует его для вызова f.

Почему A(a) отличается в обоих контекстах? Как это указано в стандарте или по какой-то неясной причине? Как я могу создать временный объект, как в первом примере кода?

Ответы

Ответ 1

Это еще один пример правила "все, что может быть объявлением является объявлением". [Stmt.ambig]/р1:

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

В стандарте представлены следующие примеры:

Предполагая, что T является спецификатором простого типа,

T(a)->m = 7;       // expression-statement
T(a)++;            // expression-statement
T(a,5)<<c;         // expression-statement
T(*d)(int);        // declaration
T(e)[5];           // declaration
T(f) = { 1, 2 };   // declaration
T(*g)(double(3));  // declaration

В последнем примере выше, g, который является указателем на T, инициализируется до double(3). Это, конечно, плохо сформировано по семантическим причинам, но что не влияет на синтаксический анализ.

а также:

class T {
// ...
public:
    T();
    T(int);
    T(int, int);
};

T(a);          // declaration
T(*b)();       // declaration
T(c)=7;        // declaration
T(d),e,f=3;    // declaration
extern int h;
T(g)(h,2);     // declaration

Простейшим способом устранения неоднозначности является, вероятно, дополнительный набор круглых скобок. (A(a)); однозначно является выражением-выражением.

Ответ 2

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

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

Если вы действительно хотите контролировать уничтожение своего объекта, вы всегда можете инкапсулировать его в блок: { A tmp(a); } // temporary A object


Вещь... Я не вижу смысла делать это. Почему вы хотите создать временный объект, не используя его? Обычно это означает, что у вашего создания или уничтожения объекта есть некоторые побочные эффекты, которые вы хотите вызвать. Это действительно плохая идея! Вы должны переместить побочные эффекты в функцию и просто вызвать ее.