自动变量的“创建点”

4
void foo()  
{  
    //some code

    MyClass m();

    //some more code
}

C++标准是否保证在运行//some code之后才会调用MyClass类的构造函数,还是这是未指定的行为?

我指的是调用真正构造函数的声明, Myclass m(1,2, true); 保留错误,因为这是一个好点。 - Boaz
5个回答

4

对于这个问题的技术答案是编译器将确保构造函数完全不被执行,因为这一行代码

MyClass m();

不是变量声明。相反,它是一个名为m的函数的原型,该函数不带参数并返回一个MyClass对象。要将其转换为对象,您需要删除括号:

MyClass m;

由于这是一个常见的混淆点,在C++11中有一种新的语法可以用于初始化自动对象。与其使用括号,不如使用花括号,就像这样:
MyClass m{};

这告诉编译器使用MyClass的无参构造函数,因为没有办法将上述内容解释为函数原型。

如果您进行此更改,编译器将保证在第一段代码之后和第二段代码之前执行m的构造函数。

希望这可以帮到您!


3

首先,MyClass m();并不会创建任何对象,你可能想要使用的是MyClass m;。是的,在运行//some code之后保证会创建对象。


你对哪一部分持不同意见?是函数原型部分,还是执行顺序的安排? - templatetypedef
1
@LuchianGrigore:如果对象根本没有被使用或编译器认为可以进行优化,那么编译器可以自由地优化对象的创建。然而,如果需要创建对象,则OP代码的执行顺序是固定的。对象将仅在执行//some code之后且在执行//some more code之前被创建。 - Alok Save
@LuchianGrigore:这里的问题不在于编译器可以优化掉构造函数调用的事实,而在于语句执行的顺序。如果必须调用构造函数,它只能在上述代码之后被调用,没有其他方式。 - Alok Save
@Als 我不会对问题的意图进行猜测。 - Luchian Grigore
@Als 无论如何,我已经编辑了我的答案,即使构造函数没有被优化掉。 - Luchian Grigore
显示剩余7条评论

1

这里没有创建任何对象。

MyClass m();

声明一个名为m的函数,该函数不接受任何参数并返回一个类型为MyClass的对象。

MyClass m

将创建一个名为mMyClass类型对象,是的,保证只有在执行该行代码时才会调用m的构造函数。


0

假设你想要声明一个变量,正如已经提到的:

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

从语义上讲,构造函数在{before}之后和{after}之前执行。

在执行过程中是否保持这种顺序由“as-if”规则覆盖。也就是说,为了允许优化,标准仅提供关于可观察效果的保证:无论选择哪种执行模型,可观察效果都应该像没有进行任何优化一样。

可观察效果包括但不限于:

  • volatile变量的修改
  • 系统调用(包括内存操作)

默认情况下,一个定义未知的函数被认为具有可观察效果。

值得注意的例外是“复制省略”优化,即使复制构造函数可能具有可观察效果,标准也允许在许多情况下使用它。

具体来说,这意味着给定:

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

MyClass m(); --> 这里并没有创建对象,只是声明了一个不带参数但返回MyClass对象的函数。

如果你需要创建一个对象,只需写MyClass m;或者MyClass *m = new MyClass(); 是的,在一些代码之后会调用MyClass的构造函数。


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