我目前正在用c ++编写一段代码,我遇到了一些我不太了解的行为。让我们说我有一个自定义类(我不确定它是否与类中的内容有关)并且我想指向这个类:
AliAODEvent* aod;
现在,在我创建了这个指针之后,我想将它分配给一个内存位置。在我使用的框架中,我想指向的对象已经存在于某处,所以我所做的是
AliAODEvent* aod = (This is where the object I want to point to goes);
我现在意识到我应该使用aod=(Object to point to);
但我很好奇当我尝试基本上"重新初始化"指针。有什么想法吗?
答案 0 :(得分:2)
在C ++中,您有声明和初始化。
int x; // Declaration
x = 10; // Initialisation
声明变量意味着要求操作系统为其分配内存中的位置。初始化变量意味着第一次在该存储器地址处设置值。你可以一次做两件事:
int x = 10; // Declares x, then initialises it to 10
在C ++中,不允许多次声明变量:
int x; // Declares x
int x; // Tries to declare another variable also called x, fails (ERROR)
但是,只要它们位于不同的范围内,您就可以声明两个具有相同名称的变量:
#include <iostream>
int x = 10;
int main()
{
int x = 20;
{
int x = 30;
std::cout << x << ", " << ::x << std::endl; // Prints '30, 10'
}
std::cout << x << ", " << ::x << std::endl; // Prints '20, 10'
return 0;
}
{}表示新范围,::表示全局范围。因此,您可以指定全局范围,或者可以使用本地范围,但不能使用具有相同名称的任何其他内容。
答案 1 :(得分:1)
在C ++中,语句
AliAODEvent* aod = (This is where the object I want to point to goes);
表示“请为我创建一个名为aod
AliAODEvent*
的新变量,并为其指定一个特定变量。”另一方面,声明
aod = (This is where the object I want to point to goes);
表示“查找名为aod
的现有变量,并将其指定为指向新位置。”这里的区别在于,通过包含类型的名称,C ++认为你提供了一个引入新变量的声明,而不是一个赋值语句现有变量和变化点。这就是语言的设计方式。
第二个工作原理而第一个工作的原因是你最终试图采取存在的东西并改变它,这意味着你应该不提供声明。一般来说,如果要声明该变量,则只应在声明中包含变量的类型,否则只应使用其名称。
答案 2 :(得分:0)
在这种情况下,您不是要重新初始化指针,而是尝试创建一个同名的指针,这将是一个错误,除非它位于不同的作用域块中。
即:
AliAODEvent* aod;
{
AliAODEvent* aod = (something)
}
在这种情况下,aod变量可以正常(尽管可能会显示警告),因为它是一个不同的变量,一旦它的范围('}')结束就不再存在了。
答案 3 :(得分:0)
以下代码:
A* aod = &x;
A* aod = &y;
声明两个变量,并且格式错误。它应该被大多数编译器拒绝,但是使用正确的设置,一些编译器可能会让它通过。
这里发生的事情是编译器为第一个变量创建了存储空间并将x
的地址存储到其中。然后,它为第二个变量创建附加存储,并为隐藏原始变量。
此时,程序将x
和y
的值都存储在不同的内存位置,但只有在超出范围时才能引用第二个aod
这通常称为“阴影”,仅在范围之间合法:
#include <iostream>
struct A {};
A a, b, c;
A* ptr = &a;
void report(A* p) {
std::cout << (void*) &a << ", " << (void*) &b << ", " << (void*) &c
<< ": " << (void*) p << "\n";
}
int f() {
std::cout << "f() ";
report(ptr);
}
int main() {
report(ptr);
if (ptr != nullptr) {
A* ptr = &b;
report(ptr);
if (ptr != nullptr) {
A* ptr = &c;
f();
report(ptr);
}
report(ptr);
}
report(ptr);
}
另外,请注意指针不智能。
A* aod = new A;
aod = new A;
这会分配两个A
但从不释放第一个,因为我们从不告诉它,我们只是覆盖该值。编译器不跟踪动态对象何时不再被引用。
int main() {
A* aod = nullptr;
if (aod == nullptr) { // start new scope
A x;
aod = &x;
} // end scope, `x` is destroyed.
use(aod);
}
此代码引入了一个错误:aod
指向x
的地址,但x
在超出}
范围时被销毁,因此此指针为dangling
并引用无效内存。
答案 4 :(得分:0)
在为指针指定现有位置的地址时,您不希望再次使用其左侧的类型说明符,因为该变量已存在(即声明变量)。当您处于第一个aod
的范围内时,您将无法再次声明新变量aod
。
此外,要明确的是,如果您在分配运算符之后具有对象的地址,那么aod=(Object to point to);
只是正确的,不对象本身。您可以使用&
运算符在另一个对象的名称之前将对象的地址分配给指针,以获取其地址:
Object* objectPointer = &existingObject; //point objectPointer to the address of existingObject
或者,通过一种方法,
Object* objectPointer = method()
其中method()
的返回类型为Object*
(指向Object
类型的指针)。
您还可以使用new
运算符在堆上创建新对象:
Object* objectPointer = new Object("args");
,完成后必须使用delete
运算符删除。
delete objectPointer;
请记住,仅仅因为指针超出范围并停止存在,并不意味着它所指向的内存。