[英]why in c++ there are no compile-time error if class field is not initialized?
[英]C++: Are classes/structs ever initialized at compile-time?
假设我用构造函数Foo(int)
编写了一个Foo
类。 我有这段代码:
Foo a(i), b = a + Foo(2);
如果我在代码中使用常量(例如Foo(2)
调用构造函数,则编译器是否会运行一次并存储结果供运行时使用,还是在运行时执行? struct / class是否仅包含POD数据类型是否相同?
假设它在运行时执行(我相信是这样),是否有办法使其在编译时运行,或者具有与运行时相同的效果?
编辑 :恐怕我没有把自己弄清楚。 我指的是Foo(2)
部分的代码,它是完全不变的。 另外,我无法使用C ++ 11(我正在使用GCC 4.1,并且无法升级),因此constexpr
虽然有效,但不适合我。
这是可能有你的a
使用constant initialization
,这是静态初始化,但要做到这一点:
i
最常表达 Foo::Foo(int)
必须是constexpr
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
可能是可能a
,但我对b
的把握却很少。
假设我用构造函数Foo(int)编写了一个类Foo。 我有这段代码:
Foo a(i), b = a + Foo(2);
如果我在代码中使用常量调用构造函数,那么编译器是否会运行一次并存储结果供运行时使用,还是在运行时执行?
这有两个层次:
i
是编译时间常数吗? 如果不是,并且将i
的值传递给Foo::Foo(i)
影响其行为(是否影响数据成员值或诸如日志记录之类的副作用),那么显然在编译时构造Foo(i)本质上是不可能的。 如果i
为常数,则从本质上来说仍然是不可能的-例如,构造函数的实现可能具有基于当前时间的行为,或者需要查询其他一些运行时数据。 这样的问题也可能阻止Foo(2)
在编译时进行评估。
如果i
是常量,并且Foo
的构造函数不依赖于其他仅运行时的数据,则可以进行优化。 但是,您的代码中没有什么要求C ++标准甚至可以尝试任何优化,更不用说能够对其进行优化了。 在Foo
上调用+
运算符的情况也是如此……优化可能是合法的,但当然不是必需的。
在实践中,我希望当前大多数主流编译器都可以针对编译时常数i
优化Foo(i)
简单情况,但是会遇到解决该问题的挑战。 如果您真的想知道,请在各种优化级别上为您的编译器尝试一下。
假设它在运行时执行(我相信是这样),是否有办法使其在编译时运行,或者具有与运行时相同的效果?
是的...您可能会从constexpr
得到一些好处,这是C ++ 11引入的一个关键字,它告诉编译器在编译时需要解析某些值(如果您对变量/值使用constexpr
,则表明编译器不是需要在编译时提供支持,它将报告错误)。
其次,通常可以使用模板来表达编译时操作。 为了使自己朝这个方向开始,您可能需要搜索“ C ++模板阶乘编译时间”或类似内容,以了解如何对基本计算进行编码。
适用“假设”规则,该规则表示只要程序的可观察行为与标准中描述的行为相同,编译器就可以执行其喜欢的任何事情。
如果:
Foo
的构造函数在TU中可见, ~Foo
也是如此 operator+
是可见的,并且不会做任何事情来使RHS的地址“转义”到未知代码中,或使用其地址进行可观察到的行为(例如将其打印出来),或执行任何其他需要对象实际存在的操作, 那么足够聪明的优化器可以完全消除Foo(2)
临时性,并且无论operator+
使用RHS的数据成员如何,只要使用它知道这些成员将拥有的任何值即可。
或者,作为次要的优化,它可以将值放入程序的数据部分中Foo
实例的布局中,并将其用作Foo(2)
。 我想这就是将结果存储为运行时的含义。
这些优化是否真正发生完全取决于实现,并且取决于您使用的编译器和标志。 分解代码以查看实际情况。
如果执行以下操作,则可以确保在C ++ 03中仅对Foo(2)
进行一次计算:
static Foo foo2(2);
Foo a(i), b = a + foo2;
foo2
是(根据标准)在运行时(第一次执行代码)计算的。 同样,编译器可以在编译时调用“假设”规则来进行部分或全部计算,但这并不是必需的。
Foo a(i), b = a + Foo(2);
初始化发生在运行时,而不是编译时。
如果可以在编译时计算其初始化程序,或者将其声明为全局变量或static
,则编译时初始化仅适用于内置类型。 在后两种情况下,它们在编译时为零。 我在这里详细解释了这一点:
在执行过程中,可以在不同的位置调用已编译的代码。 编译代码后,Foo(2)的值可能是不可变的。
这在运行时发生。 如果您希望它在编译时发生,那么您需要对值进行硬编码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.