简体   繁体   English

C ++:类/结构是否曾经在编译时初始化?

[英]C++: Are classes/structs ever initialized at compile-time?

Let's say I write a class Foo with a constructor Foo(int) . 假设我用构造函数Foo(int)编写了一个Foo类。 And I have this piece of code: 我有这段代码:

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

If I call the constructor in the code with a constant, eg Foo(2) , does the compiler run it once and store the result for run-time, or is it executed at run-time? 如果我在代码中使用常量(例如Foo(2)调用构造函数,则编译器是否会运行一次并存储结果供运行时使用,还是在运行时执行? Is it the same whether or not the struct/class contains only POD data types? struct / class是否仅包含POD数据类型是否相同?

Assuming that it executes at run-time (which I believe to be the case), is there a way to make it run at compile-time, or have the same effects as if it were run as such? 假设它在运行时执行(我相信是这样),是否有办法使其在编译时运行,或者具有与运行时相同的效果?

Edit : I'm afraid I didn't make myself clear. 编辑 :恐怕我没有把自己弄清楚。 I am referring to the Foo(2) part for the code, which is completely immutable. 我指的是Foo(2)部分的代码,它是完全不变的。 Also, I am unable to utilise C++11 (I am working with GCC 4.1 and cannot upgrade), so constexpr , while valid, is unsuitable for me. 另外,我无法使用C ++ 11(我正在使用GCC 4.1,并且无法升级),因此constexpr虽然有效,但不适合我。

It's possible to have your a use constant initialization , which is static initialization, but for that to happen: 这是可能有你的a使用constant initialization ,这是静态初始化,但要做到这一点:

  1. i most be a constant expression i最常表达
  2. Foo::Foo(int) must be constexpr Foo::Foo(int)必须是constexpr
  3. Any/all other functions/ctors used by Foo:Foo(int) must also be constexpr . Foo:Foo(int)使用的所有其他/所有函数/变量也必须是constexpr

The same would be pretty much the case for your b -- Foo(2) would have to be constexpr , and Foo::operator+(Foo const &) or Foo operator+(Foo const &, Foo const &) (whichever you have) would have to be constexpr . 对于您的b来说,情况几乎相同Foo(2)必须为constexpr ,而Foo::operator+(Foo const &)Foo operator+(Foo const &, Foo const &) (无论您拥有什么)将必须是constexpr

The definition of a constant expression is at §5.19 of the C++11 standard, in case you want to investigate in more detail. 如果要更详细地研究,常量表达式的定义在C ++ 11标准的第5.19节中。 My immediate guess is that if Foo is fairly simple, it's probably possible for a , but I'm a lot less certain about b . 我的直接猜测是,如果Foo非常简单,那么a可能是可能a ,但我对b的把握却很少。

Let's say I write a class Foo with a constructor Foo(int). 假设我用构造函数Foo(int)编写了一个类Foo。 And I have this piece of code: 我有这段代码:

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

If I call the constructor in the code with a constant, does the compiler run it once, and store the result for run-time, or is it executed at run-time? 如果我在代码中使用常量调用构造函数,那么编译器是否会运行一次并存储结果供运行时使用,还是在运行时执行?

There are two levels to this: 这有两个层次:

  • is it possible and legal wrt the Standard for a perfect optimiser -- achieving everything an expert person could potentially do with unlimited effort and genius - to do this at compile time, and 是否有可能通过法律为完善的优化程序制定标准-是否可以不费吹灰之力和天才地实现专家可以做的所有事情-在编译时做到这一点,以及
  • is compile-time behaviour required / guaranteed by the Standard. 是标准要求 / 保证的编译时行为。

Is i a compile time constant? i是编译时间常数吗? If not, and the value of i passed to Foo::Foo(i) influence its behaviour (whether affecting data member values or side-effects like logging), then clearly it's inherently impossible to construct Foo(i) at compile time. 如果不是,并且将i的值传递给Foo::Foo(i)影响其行为(是否影响数据成员值或诸如日志记录之类的副作用),那么显然在编译时构造Foo(i)本质上是不可能的。 If i is constant, it may still be inherently impossible - for example the constructor implementation may have behaviour based on the current time, or need to consult some other run-time data. 如果i为常数,则从本质上来说仍然是不可能的-例如,构造函数的实现可能具有基于当前时间的行为,或者需要查询其他一些运行时数据。 Such problems may also prevent Foo(2) being possible to evaluate at compile-time. 这样的问题也可能阻止Foo(2)在编译时进行评估。

If i is constant, and Foo 's constructor doesn't depend on other runtime-only data, then it is possible to optimise. 如果i是常量,并且Foo的构造函数不依赖于其他仅运行时的数据,则可以进行优化。 But, there's nothing in your code that requires the C++ Standard to even attempt any optimisation, let alone be capable of optimising this away. 但是,您的代码中没有什么要求C ++标准甚至可以尝试任何优化,更不用说能够对其进行优化了。 The same is true of the + operator invoked on the Foo s... it may be legal to optimise, but is certainly not required. Foo上调用+运算符的情况也是如此……优化可能是合法的,但当然不是必需的。

In practice, I would expect most current mainstream compiler to optimise simple cases of Foo(i) for compile-time constant i , but be challenged by resolving the addition. 在实践中,我希望当前大多数主流编译器都可以针对编译时常数i优化Foo(i)简单情况,但是会遇到解决该问题的挑战。 If you really want to know, try it for your compiler at various optimisation levels.... 如果您真的想知道,请在各种优化级别上为您的编译器尝试一下。

Assuming that it executes at run-time (which I believe to be the case), is there a way to make it run at compile-time, or have the same effects as if it were run as such? 假设它在运行时执行(我相信是这样),是否有办法使其在编译时运行,或者具有与运行时相同的效果?

Yes... you may get some milage out of constexpr , which is a keyword introduced with C++11 that tells the compiler it's required to resolve certain values at compile time (if you constexpr for variables/values that the compiler isn't required to support at compile time it will report an error). 是的...您可能会从constexpr得到一些好处,这是C ++ 11引入的一个关键字,它告诉编译器在编译时需要解析某些值(如果您对变量/值使用constexpr ,则表明编译器不是需要在编译时提供支持,它将报告错误)。

Secondly, it's often possible to express compile time operations using templates. 其次,通常可以使用模板来表达编译时操作。 To get yourself started in that direction, you may want to search for "C++ template factorial compiletime" or similar to see how basic calculations can be coded. 为了使自己朝这个方向开始,您可能需要搜索“ C ++模板阶乘编译时间”或类似内容,以了解如何对基本计算进行编码。

The "as-if" rules applies, which says that the compiler can do anything it likes, provided that the observable behavior of the program is the same as that described in the standard. 适用“假设”规则,该规则表示只要程序的可观察行为与标准中描述的行为相同,编译器就可以执行其喜欢的任何事情。

If: 如果:

  • the constructor of Foo is visible in the TU, Foo的构造函数在TU中可见,
  • so is the destructor ~Foo , 析构函数~Foo也是如此
  • neither of them has any side-effects, 他们两个都没有任何副作用,
  • their results don't depend on anything that needs to be worked out at runtime (like the time, or the value of some non-const object that for all we know might have been modified by the point your code is executed), 它们的结果不依赖于运行时需要解决的任何问题(例如时间,或者众所周知,某些非常量对象的值可能已经在执行代码时被修改了),
  • operator+ is visible, and doesn't do anything to let the address of the RHS "escape" into unknown code, or use its address for observable behavior (such as printing it out), or do anything else that requires the object actually be there, operator+是可见的,并且不会做任何事情来使RHS的地址“转义”到未知代码中,或使用其地址进行可观察到的行为(例如将其打印出来),或执行任何其他需要对象实际存在的操作,

then a sufficiently clever optimizer could eliminate the Foo(2) temporary entirely, and wherever operator+ uses the data members of the RHS, just use whatever values it knows those members will have. 那么足够聪明的优化器可以完全消除Foo(2)临时性,并且无论operator+使用RHS的数据成员如何,只要使用它知道这些成员将拥有的任何值即可。

Or, as a lesser optimization, it could put the values into the layout of an instance of Foo in a data section of the program, and use that as Foo(2) . 或者,作为次要的优化,它可以将值放入程序的数据部分中Foo实例的布局中,并将其用作Foo(2) I guess that's what you mean by storing the result for runtime. 我想这就是将结果存储为运行时的含义。

Whether such optimizations actually happen is completely implementation-specific, and depends what compiler you use and what flags. 这些优化是否真正发生完全取决于实现,并且取决于您使用的编译器和标志。 Disassemble the code to see what really happens. 分解代码以查看实际情况。

You can ensure that Foo(2) is computed only once in C++03, if you do something like: 如果执行以下操作,则可以确保在C ++ 03中仅对Foo(2)进行一次计算:

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

foo2 is (according to the standard) computed at runtime, the first time the code is executed. foo2是(根据标准)在运行时(第一次执行代码)计算的。 Again, the compiler could invoke the "as-if" rule to do some or all of the computation at compile-time, but again this isn't required. 同样,编译器可以在编译时调用“假设”规则来进行部分或全部计算,但这并不是必需的。

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

This initialization happens at runtime, not at compile-time. 初始化发生在运行时,而不是编译时。

Compile-time initialization happens only for built-in types, iftheir initializer can be computed at compile-time, or if they are declared as global variables, or as static . 如果可以在编译时计算其初始化程序,或者将其声明为全局变量或static ,则编译时初始化仅适用于内置类型。 In the latter two cases, they are zero-intialized at compile-time. 在后两种情况下,它们在编译时为零。 I've explained this in detail here: 我在这里详细解释了这一点:

The code which has been compiled may be called at different points during the execution process. 在执行过程中,可以在不同的位置调用已编译的代码。 Once the code is compiled, Foo(2)'s value might be immutable. 编译代码后,Foo(2)的值可能是不可变的。

This happens at run time. 这在运行时发生。 If you want it to happen at compile time then you need to hard code the value. 如果您希望它在编译时发生,那么您需要对值进行硬编码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM