c++ 中块内局部变量的存储分配
我想知道编译器在什么时候为块内的局部变量分配存储空间。 goto 和 switch 如何跳过构造函数? :
class Tree {/*...*/}
...
void foo (int i){
if (i < 10) goto label; //illegal: cannot jump past a ctor
Tree t (45);
label:
switch (i){
case 1:
Tree t2 (45);
break;
case 2: //illegal: cannot jump past ctor
Tree t3 (45);
break;
}
}
虽然上面的代码不适用于用户定义的对象,但如果我用内置对象替换它们,它就可以工作。这是为什么?
编辑: 内置对象,如 int、char 等。 我得到的错误(ubuntu 上的 g++ 4.5):
jumpPastConstructor.c++: In function ‘void foo(int)’:
jumpPastConstructor.c++:26:3: error: jump to label ‘label’
jumpPastConstructor.c++:24:20: error: from here
jumpPastConstructor.c++:25:10: error: crosses initialization of ‘Tree t’
jumpPastConstructor.c++:31:16: error: jump to case label
jumpPastConstructor.c++:29:25: error: crosses initialization of ‘Tree t2’
I want to know at which point the compiler allocates storage for local variables inside a block. How does goto and switch jump past a constructor? :
class Tree {/*...*/}
...
void foo (int i){
if (i < 10) goto label; //illegal: cannot jump past a ctor
Tree t (45);
label:
switch (i){
case 1:
Tree t2 (45);
break;
case 2: //illegal: cannot jump past ctor
Tree t3 (45);
break;
}
}
While the above code does not work for user-defined objects it works if i replace them with built-in objects. Why is that?
Edit:
Built in objects like int, char, etc.
The errors i get (g++ 4.5 on ubuntu):
jumpPastConstructor.c++: In function ‘void foo(int)’:
jumpPastConstructor.c++:26:3: error: jump to label ‘label’
jumpPastConstructor.c++:24:20: error: from here
jumpPastConstructor.c++:25:10: error: crosses initialization of ‘Tree t’
jumpPastConstructor.c++:31:16: error: jump to case label
jumpPastConstructor.c++:29:25: error: crosses initialization of ‘Tree t2’
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
6.7/3:
重要的不是何时分配存储,而是何时调用构造函数。跳过构造函数的 goto 将是一个问题,这就是它被禁止的原因。 (没有初始化器的 POD 类型不需要任何构造,因此是允许的。)
6.7/3:
What matters is not when the storage is allocated, but when the constructor is called. A goto that jumped past a constructor would be a problem, which is why it's banned. (POD types with no initialiser don't need any construction, so they're allowed.)
问题的第一部分很简单:大多数编译器将所有本地分配整理成单个堆栈分配,然后对该分配进行分区。仅当它们进入范围或显式初始化时才会发生初始化。
从编码的角度来看,您的示例非常糟糕,因为您跳过了
x
进入范围的点,因此构造函数永远不会被调用(这就是goto
是坏)以及为什么你的编译器告诉你停止尝试滥用它。但是,某些类型可以保持未初始化,例如int
、float
等内置类型。您会收到警告,这就是为什么并非所有类型都会抛出异常如果跳过其初始化(构造函数),则会出现错误。the first part of the question is easy: most compilers collate all local allocations into a single stack allocation and then partition off that allocation. the initialization happens only when they come into scope or they are explicitly initialized.
Your example is pretty bad from a coding point of view, as you jump over the point at which
x
comes into scope, thus the constructor will never be called (this is one of the reasons whygoto
is bad) and why your compiler is telling you to stop trying to abuse it. However, certain types can be left uninitialized, such as the built-in types ofint
,float
etc. you'll instead get a warning, which is why not everything throws an error if you jump over its initialization (constructor).转换为 xx.cpp 中的可编译代码:
并按 MacOS X 10.6.8 上的 G++ 4.6.0 所示进行编译,会产生所示错误:
每个变量
x
、有一个默认构造函数>x2
和x3
。C++ 标准只是简单地规定,不允许您跳入变量构造之后的块。有效的方法是:
使用三对额外的大括号,您不再跳到声明和初始化变量的块,因此代码是合法的,并且可以在前面显示的命令行下干净地编译。
Converted into compilable code in xx.cpp:
and compiled as shown with G++ 4.6.0 on MacOS X 10.6.8 yields the errors shown:
There is a default constructor for each of the variables
x
,x2
, andx3
.And the C++ standard simply says you are not allowed to jump into a block past variable construction. What would work is:
With the three extra pairs of braces, you are no longer jumping into the blocks where the variables are declared and initialized, so the code is legitimate and compiles cleanly under the command line shown before.
这里的解决方案是:为每个CASE添加括号
}
我不知道这有什么疯狂的!!!!但是添加 { 和 } 可以解决这个问题!
Solution here is: Add bracket to each CASE
}
I don't know what crazy is this!!!! But Add { and } could solve this issue!
您不能跨构造函数
goto
或case
。内置函数没有构造函数。编译器知道当它进入函数时其局部变量的总空间需求是多少,并且它将移动堆栈指针以容纳它们。该内存未初始化。
它在函数流程中根据需要调用构造函数和析构函数。这就是为什么你不能像这样使用
goto
或case
—— 它破坏了不变量。诸如break
之类的语句根据需要在 for 循环中调用析构函数,并且一切正常。You can't
goto
orcase
across constructors. Builtins don't have constructors.The compiler knows when it enters the function what the total space requirement of its local variables is, and it will move the stack pointer to accommodate them. This memory is uninitialised.
It calls the constructors and destructors during the function flow as it needs to. This is why you can't use
goto
orcase
like that -- it breaks the invariants. Statements such asbreak
call destructors as necessary in, say, a for-loop, and everything works out OK.我来到这里是因为我遇到了同样的问题。
对我有帮助的是把“树”移到
case
外面。并且不是
Tree t2 (45);
而是将Tree t2;
放在switch
之前。以及
case 1
内的t2 (45);
。然后您需要对
Tree t3 (45);
执行相同的操作。I came here because I had the same problem.
What helped for me was to decare the 'Tree' outside the
case
.And to not
Tree t2 (45);
but to placeTree t2;
beforeswitch
.And
t2 (45);
insidecase 1
.And then you need to do the same for
Tree t3 (45);
.