And*_*owl 21 c++ static-typing dynamic-typing language-lawyer c++11
我曾经认为这个问题的答案是" 100% ",但我最近指出了一个让它值得思考的例子.考虑声明为具有自动存储持续时间的对象的C数组:
int main()
{
int foo[42] = { 0 };
}
Run Code Online (Sandbox Code Playgroud)
这里的类型foo很明显int[42].相反,请考虑以下情况:
int main()
{
int* foo = new int[rand() % 42];
delete[] foo;
}
Run Code Online (Sandbox Code Playgroud)
这里foo是is 的类型int*,但是如何在编译时告诉表达式创建new的对象的类型?(重点是强调我不是在谈论new表达式返回的指针,而是关于表达式创建的数组对象new).
这就是C++ 11标准的第5.3.4/1段规定了new表达式的结果:
[...]由new-expression创建的实体具有动态存储持续时间(3.7.4).[注意:此类实体的生命周期不一定限于创建它的范围.-end note]如果实体是非数组对象,则new-expression返回指向所创建对象的指针.如果它是一个数组,则new-expression 返回一个指向数组初始元素的指针.
我以前认为在C++中所有对象的类型都是在编译时确定的,但上面的例子似乎反驳了这种信念.另外,根据第1.8/1段:
[...] 创建对象时确定对象的属性.对象可以有一个名称(第3条).对象的存储持续时间(3.7)会影响其生命周期(3.8).对象具有类型(3.9).[...]
所以我的问题是:
如果有人能够至少详细说明上述一点,那就太好了.
编辑:
标准似乎清楚地表明new表达式确实创建了一个数组对象,而不仅仅是像一些人指出的那样将几个对象布局为数组.根据第5.3.4/5段(由Xeo提供):
当分配的对象是数组时(即,使用noptr-new-declarator语法或new-type-id或 type-id表示数组类型),new-expression产生指向初始元素的指针(如果任何)数组.[注:既
new int与new int[10]具有类型int*和类型new int[i][10]是int (*)[10]末端音符]的属性说明符-SEQ的noptr新声明符 appertains 到相关联的阵列型.
的新的表达不会产生与运行时间变化的阵列类型的对象.它创建了许多对象,每个对象都是静态类型int.静态地不知道这些对象的数量.
C++为动态类型提供了两种情况(第5.2.8节):
这些都没有给出new int[N]动态数组类型创建的任何对象.
小心地,对new-expression的评估会创建无数个重叠的数组对象.从3.8p2:
[注意:一旦获得具有适当大小和对齐的存储,数组对象的生命周期就会开始,并且当数组占用的存储被重用或释放时,其生命周期结束.12.6.2描述了基础和成员子对象的生命周期. - 结束说明]
所以,如果你想谈论由创建的"数组对象" new int[5],你必须给它不仅类型int[5],而且int[4],int[1],char[5*sizeof(int)],和struct s { int x; }[5].
我认为这相当于说运行时不存在数组类型.对象的类型应该是限制性的,信息,并告诉你一些关于它的属性.允许将内存区域视为具有不同类型的无限数量的重叠数组对象,这意味着该数组对象是完全无类型的.运行时类型的概念仅对存储在数组中的元素对象有意义.
术语"静态类型"和"动态类型"适用于表达式.
静态类型
在不考虑执行语义的情况下对程序进行分析得到的表达式(3.9)的类型
动态类型
<glvalue>由glvalue表达式表示的glvalue所指向的最派生对象(1.8)的类型
此外,您可以看到动态类型仅在静态类型可以派生时与静态类型不同,这意味着动态数组类型始终与表达式的静态类型相同.
所以你的问题:
但是如何在编译时告诉新表达式创建的对象的类型?
对象具有类型,但它们不是"静态"或"动态"类型,缺少引用该对象的表达式.给定一个表达式,静态类型在编译时始终是已知的.在没有派生的情况下,动态类型与静态类型相同.
但是你要问的是对象的类型与表达式无关.在示例中,您已经要求创建一个对象,但是您没有指定要在编译时创建的对象类型.你可以这样看:
template<typename T>
T *create_array(size_t s) {
switch(s) {
case 1: return &(*new std::array<T, 1>)[0];
case 2: return &(*new std::array<T, 2>)[0];
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
关于这一点没什么特别或独特的.另一种可能性是:
struct B { virtual ~B() {}};
struct D : B {};
struct E : B {};
B *create() {
if (std::bernoulli_distribution(0.5)(std::default_random_engine())) {
return new D;
}
return new E;
}
Run Code Online (Sandbox Code Playgroud)
要么:
void *create() {
if (std::bernoulli_distribution(0.5)(std::default_random_engine())) {
return reinterpret_cast<void*>(new int);
}
return reinterpret_cast<void*>(new float);
}
Run Code Online (Sandbox Code Playgroud)
唯一的区别new int[]是你无法看到它的实现,看它在不同类型的对象之间进行选择来创建.
| 归档时间: |
|
| 查看次数: |
2703 次 |
| 最近记录: |