int x = 12;
12
被称为整数字面量,因此无法在LValue中使用。
- 编译器如何分配内存给字面量?
- 字面量的作用域是什么?
- 为什么我们不能在其作用域内使用 &12 来获取其地址?
好的,题目中举的是一个不好的例子。
但这个问题仍然有效:
让我们试试:
Foo getFoo() {return Foo();}
int func()
{
getFoo().bar(); // Creates temporary.
// before this comment it is also destroyed.
// But it lives for the whole expression above
// So you can call bar() on it.
}
int func2()
{
Foo const& tmp = getFoo(); // Creates temporary.
// Does not die here as it is bound to a const reference.
DO STUFF
} // tmp goes out of scope and temporary object destroyed.
// It lives to here because it is bound to a const reference.
;
)。如果绑定到const引用,则会持续到该引用所属的作用域结束(有一些例外情况(如构造函数))。int main() {12;}
编译正常。因为12是一个字面量,所以是一个有效的表达式,也是一个有效的语句。请注意,它并没有做太多事情。字面量12可能被编码成目标文件中的汇编指令。而你代码中的变量x
是一个存在于内存中的对象。 - Martin York12
是一个整数字面量。整数字面量几乎总是作为立即操作数“嵌入”在机器指令中。它们不存储在内存中,因此您无法通过地址访问它们,也没有范围。int x = 12
would translate to something like
movl 12 address_of_x_or_register
在几乎所有的架构中,12都是作为指令的一部分进行编码的。
为了明确起见,x
仍然驻留在内存中(对于局部变量来说是堆栈,在全局变量的情况下是数据段),并且最终将包含值12
。右手边的"对象"12是整数文字,它在指令执行之前或期间不驻留在内存中,而是"驻留"在指令本身中。
gcc -S foo.c
生成与你的 C 代码等效的机器码。然后查看生成的 foo.S
文件。 - jmanx
仍然驻留在内存中(对于局部变量来说是堆栈,在全局段的情况下是数据段),并且在指令执行后包含值12。RHS值12
在指令之前/期间不驻留在内存中,而是驻留在指令本身中。 - jman1. 编译器如何为临时对象分配内存?
string myString = "hello";
在这种情况下,编译器调用转换构造函数
来初始化一个新对象。
2. 临时对象的作用域是什么?
临时对象的生命周期只有到分号结束。
3. 为什么我们不能在其作用域中使用 &12 获取它的地址?(在这种情况下是 "hello")
&12
不是对象,它是传递给转换构造函数的参数。
注意,其他答案大多澄清了你的误解,但这个没有:
字面量的作用域是什么?
这个问题没有意义,因为作用域是名称的属性(变量名、函数名、类型名、模板名、命名空间名等)。
字面量是一个数字的表示法,不是一个名称。
对象是“内存中的某物”。这意味着这个“某物”占用了进程地址空间的一部分(无论是在栈上还是在“空闲”内存中)。同时,这也意味着如果需要,您可以获取它的地址。
临时对象只是对象。编译器会生成代码来创建它们,以计算表达式所需的对象:
void f(const string&);
void g()
{
f(string("Hello"));
}
调用f()的表达式将导致生成以下代码:
这其中关键的部分是在表达式求值结束时销毁临时对象。临时对象仅存在于表达式本身中(也就是它们的临时作用域)。您可以尝试类似于:const string* ps = &string("Hello")
,但您的编译器可能会发出警报,因为这样的表达式将导致创建指针,该指针引用已经不再被临时对象占用的内存。它可能仍然包含字符串对象成员,或者可能被程序中后续的表达式覆盖(更不用说临时对象的销毁将释放堆中由对象分配的内存)。使用ps
将导致未定义的行为。
int x = 12
这样的表达式中对象的性质。在这种情况下,x 可能是一个对象或者可能不是。这取决于编译器设置和代码跟随该行的情况。编译器可能决定将x放置在寄存器中。在这种情况下,x将不是一个对象,因为寄存器没有地址(至少在大多数平台上)。如果您不改变x
的值,编译器甚至可以决定直接在指令中使用12。因此,“12”只存在于指令代码的一部分。int x = 12
都不会创建临时的12
对象。如果编译器决定将12放入内存中,则指令将如下(伪代码):store immediate address_of_x, 12
如果将x放在寄存器中,则会得到:
move immediate regX, 12
12
根本不是一个对象,x
也不是。你可能想选择一个更好的例子,比如一个真正的对象。 - paxdiablox
在 C++ 对象模型下指代一个对象。它由定义语句创建,具有存储期和类型。请参阅 C++11 标准中的第 1.8 节“C++ 对象模型”。在问题中,“对象”一词使用的就是这个意义,而不是面向对象编程中的“对象”的意思。 - bames53