如何在C++中创建临时对象

17

我有以下代码。

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)在两个上下文中不同?这在标准中是如何规定的,还是出于某种不明原因?如何像第一个代码示例中那样构造临时对象?


3
你是否尝试在第一个例子中使用 A{a};,因为它是最令人困惑的解析的例子?你也可以尝试使用 void 强制转换:static_cast<void>(A(a)); - myaut
@jakber 我想让 temp 在这条语句之后立即销毁。如果我给它命名,那是不会发生的。 - Hot.PxL
jakber: 不,那么它将存在直到作用域的结束。Hot Pxl希望它在语句结束时被销毁。 - gpvos
请注意,如果您使用数字初始化A,它将起作用,并且如果您将int a;放在主函数内部,则会出现重新定义a的错误。 - ArnonZ
如果A有一个接受initializer_list的构造函数,那么@myaut A{a}将无法工作。第二个方法虽然可行,但使用static_cast有点丑陋。我想知道为什么会出现这种情况。 - Hot.PxL
显示剩余2条评论
2个回答

20
这是“任何可作为声明的都是声明”的另一个实例。[stmt.ambig]/p1:

语法中存在表达式语句和声明的歧义:如果一个表达式语句的最左子表达式是函数风格的显式类型转换(5.2.3),那么它可能无法与以 ( 开头的第一个声明符区分开来,此时该语句就是一个声明。

标准提供了以下示例:

Assuming T is a simple-type-specifier,

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

In the last example above, g, which is a pointer to T, is initialized to double(3). This is of course ill-formed for semantic reasons, but that does not affect the syntactic analysis.

还有:

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)); 明确地是一个表达式语句

1
如果这个答案包含了“最令人困惑的解析”关键词,并附带维基百科的链接,我认为它会更好。 - Fabio says Reinstate Monica
A { a }; 是什么意思? - paulm

5

我想不到一种方法来创建一个临时变量,而不像你在函数中那样使用它。

为什么不创建一个命名变量呢?考虑到您的声明方式,它的生命周期将与您的“临时”完全相同。

如果您真的想控制对象的销毁,您可以将其封装在块中:{ A tmp(a); } // 临时A对象


问题是...我看不出这样做有什么意义。为什么要创建一个不使用的临时对象?这通常意味着您的对象创建或销毁具有某些副作用,您想要触发它们。这是一个非常糟糕的想法!您应该将副作用移动到函数中并简单地调用它。


你说得对,我应该使用一个函数。我只是好奇为什么一个临时变量不能起作用。我从一些RTTI代码中得到了这个想法。但我想这毕竟不是一个好主意。 - Hot.PxL
@VincentRobert 我同意你的观点,我也在想像 function( A() ) 或者 return A() 这样的操作是否会影响传递给函数或从函数返回的副本。我的意思是,在复制之前还是之后对象被销毁了?如果对象在复制之前被销毁,那么你将得到一个未初始化的对象副本,无论是在函数中还是作为返回值。 - Bemipefe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接