2012-05-24 51 views
0

比方说,我写了一个类Foo与构造函数Foo(int)。 我有这段代码:C++:类/结构体是否在编译时初始化?

Foo a(i), b = a + Foo(2); 

如果我调用的代码构造以恒定的,例如Foo(2),编译器是否运行一次并将结果存储为运行时,还是在运行时执行?无论结构/类是否仅包含POD数据类型,它是一样的吗?

假设它在运行时执行(我认为是这种情况),有没有办法使它在编译时运行,或者具有与运行时相同的效果?

编辑:恐怕我没有说清楚。我指的是代码的Foo(2)部分,它是完全不可变的。另外,我无法使用C++ 11(我正在使用GCC 4.1并且无法升级),所以constexpr虽然有效,但不适合我。

+0

这是在全球范围或功能? –

+3

查看'constexpr' –

+0

我正在考虑函数内的例子。我担心不得不多次评估'Foo(2)'。 –

回答

0
Foo a(i), b = a + Foo(2); 

此初始化发生在运行时,而不是在编译时。

编译时初始化仅适用于内置类型,如果它们的初始化程序可以在编译时计算,或者它们被声明为全局变量,或者作为static。在后两种情况下,它们在编译时是零初始化的。我已经在这里详细解释这一点:

-1

这发生在运行时。如果你希望它在编译时发生,那么你需要对这个值进行硬编码。

0

已编译的代码可能在执行过程中的不同位置被调用。一旦代码被编译,Foo(2)的值可能是不可变的。

+1

downvote不是因为你错了,而是因为我不明白你在说什么。 –

+0

也是错的。 'Foo(2)'的值可能取决于构造的时间,因此不是编译时常量。 – MSalters

3

很可能有你的a使用constant initialization,这是静态初始化,但要做到这一点:

  1. i大部分是常量表达式
  2. Foo::Foo(int)必须constexpr
  3. 任何/所有其他Foo:Foo(int)使用的函数/计数器也必须是constexpr

同样将是非常多的情况下,你b - Foo(2)必须是constexpr,并Foo::operator+(Foo const &)Foo operator+(Foo const &, Foo const &)(无论你有)将不得不constexpr

常量表达式的定义在C++ 11标准的§5.19中,以防您想要更详细地调查。我的猜测是,如果Foo非常简单,那么可能是a,但我对b的确信度低很多。

3

假设我用一个构造函数Foo(int)编写了一个Foo类。我有这段代码:

Foo a(i), b = a + Foo(2); 

如果我调用的代码构造以恒定的,没有编译器运行一次,并存储运行时的结果,或者是它在运行 - 执行时间?

有两个层面的:

  • 是有可能和法律w.r.t.标准的完善优化器 - 实现家居专家的人可能具有无限的努力和天才做的 - 要做到这一点,在编译时, 和
  • 是必需的编译时行为/由标准保证

i编译时间常量?如果不是,并且传递给Foo::Foo(i)i的值影响其行为(无论是影响数据成员值还是像记录日志这样的副作用),那么显然在编译时构建Foo(i)本质上是不可能的。如果i是恒定的,那么它可能仍然是不可能的 - 例如构造函数实现可能具有基于当前时间的行为,或需要查阅其他一些运行时数据。这些问题也可能会阻止在编译时进行评估。

i如果是恒定的,并且Foo的构造不依赖于其它只运行时间数据,那么它是可能优化。但是,您的代码中没有任何内容需要C++标准甚至尝试进行任何优化,更不用说能够优化这一点了。在Foo上调用的+运算符也是如此......优化可能是合法的,但肯定不是必需的。

实际上,我希望大多数当前的主流编译器优化编译时常量iFoo(i)的简单情况,但要解决这个问题。如果你真的想知道,尝试它在各种优化级别的编译器....

假设它在运行时执行(我相信是这种情况),有没有办法使它在编译时运行,还是具有与运行时相同的效果?

是......你可能会得到一些milage出constexpr,这与推出的关键字C++ 11,告诉它需要在编译时(解决某些价值观的编译器,如果你constexpr变量/值即编译器不需要在编译时支持它将报告错误)。其次,通常可以使用模板来表达编译时间操作。为了让自己开始朝这个方向发展,您可能需要搜索“C++模板阶乘编译时间”或类似的内容,以了解如何编码基本计算。

+1

正确答案。如果'Foo'是'int'和'operator +(Foo,Foo)'的简单包装,它只是一个类型安全的'int + int',编译器甚至可能会优化那个位。 – MSalters

2

适用“假设”规则,即规则说明编译器可以做任何它喜欢的事情,只要程序的可观察行为与标准中描述的行为相同即可。

如果:

  • Foo构造是在TU可见,
  • 所以是析构函数~Foo
  • 他们都不具有任何副作用,
  • 其结果穿上” t取决于需要在运行时解决的任何事情(比如时间,或者一些非const对象的值,我们知道的所有对象都可能在代码执行时被修改过),
  • operator+是可见的,并且不会做任何事情来让RHS的地址“转义”为未知代码,或者将其地址用于可观察行为(例如打印出来),或者做任何其他需要对象在那里,

然后足够聪明的优化器可以消除Foo(2)暂时完全,何operator+使用RHS的数据成员,只是用它知道这些成员将拥有的任何值。

或者,作为较小的优化,它可以将值放入程序的数据部分的Foo实例的布局中,并将其作为Foo(2)使用。我想这就是你通过存储运行时结果的意思。

这样的优化实际上是否完全是特定于实现的,并且取决于您使用的编译器以及哪些标志。反汇编代码,看看真的发生了什么。

可以确保Foo(2)在C++ 03只计算一次,如果你这样做:是(根据标准),在运行时计算

static Foo foo2(2); 
Foo a(i), b = a + foo2; 

foo2,第一时间代码执行。同样,编译器可以在编译时调用“as-if”规则来完成部分或全部计算,但这也不是必需的。