众所周知,定义堆变量时new
会获取指针而不指定名称:
Var *p = new Var("name", 1);
但是我必须稍后在程序 中清除指向的变量p
。delete p
我想声明一个堆栈变量,以便在函数退出后自动清除它,但我只想获取指针,以及以下内容:
Var v("name", 1);
Var *p = &v;
相当繁琐,说明符v
永远不会被引用。
我可以声明一个堆栈类实例并在不指定其名称的情况下获取其指针吗?
众所周知,定义堆变量时new
会获取指针而不指定名称:
Var *p = new Var("name", 1);
但是我必须稍后在程序 中清除指向的变量p
。delete p
我想声明一个堆栈变量,以便在函数退出后自动清除它,但我只想获取指针,以及以下内容:
Var v("name", 1);
Var *p = &v;
相当繁琐,说明符v
永远不会被引用。
我可以声明一个堆栈类实例并在不指定其名称的情况下获取其指针吗?
这里隐藏了两个问题。第一个是:
Var *p = new Var("name", 1);
但是我必须稍后在程序中使用 delete p 清除 p 指向的变量。
我想声明一个堆栈变量,以便在函数退出后自动清除
所以在这里,您要问的是如何分配内存而无需事后明确清理它。解决方案是使用std::unique_ptr
:
std::unique_ptr<Var> p(new Var("name", 1));
瞧!unique_ptr 会自动清理自己,与原始指针相比,它几乎没有开销,并且它重载了 * 和 -> 运算符,因此您可以像使用原始指针一样使用它。如果您想了解更多信息,请搜索“C++11 智能指针”。
第二个问题是:
我只想获取指针,以及以下内容:
Var v("name", 1); Var *p = &v;
相当乏味,说明符 v 永远不会被引用。
这里的重点Var *p = &v
是完全没有必要。如果你有一个需要指针的函数,你可以&v
当场使用:
void SomeFunc(const Var* p);
// ...
Var v("name", 1);
SomeFunc(&v);
在将 &v 传递给需要指针的函数之前,无需将其放入单独的变量中。
例外情况是函数引用指针(或指向指针的指针):
void SomeFunc2(Var*& p);
void SomeFunc3(Var** p);
这些类型的函数在现代 C++ 中很少见,当您看到它们时,您应该非常仔细地阅读该函数的文档。通常,这些函数会分配内存,您必须使用其他函数显式释放它。
没有办法通过在堆栈上分配来做到这一点。但是,您可以std::make_shared
用于堆:
#include <memory>
std::shared_ptr<Var> p = std::make_shared<Var>();
以更加混乱为代价/风险,您可以避免在问题 ala 中重复代码中的类型:
Var v("name", 1), *p = &v;
您也可以潜在地使用alloca
,它由大多数系统提供并返回指向堆栈分配内存的指针,但是您必须通过一个单独的痛苦步骤将new
对象放入该内存并进行自己的对象销毁。 alloca
需要在函数内部调用,所以它是在其上创建对象的函数堆栈,而不是在准备函数参数期间(因为变量的内存可能嵌入在编译器用来准备函数参数的堆栈区域中),这使得包装到一些易于重复使用的设施中很棘手。您可以使用宏,但它们是邪恶的(请参阅 Marshall Cline 的 C++ 常见问题解答了解相关说明)。总的来说 - 不值得痛苦....
无论如何,我建议坚持使用问题中的代码,不要过度思考:使用&v
几次往往更容易,如果不是,如果基于堆栈的变量有不必要的标识符,通常没什么大不了的。
我认为没有一种方法可以在没有一些开销的情况下克服它(比如 shared_ptr)。所以写它的最短方法是:
Var v("name", 1), *p = &v;
是的,可以将地址返回给临时(即堆栈)对象并将其分配给指针。但是,编译器实际上可能会在当前作用域结束之前丢弃该对象(即导致内存中的该部分被覆盖)。(澄清:这意味着永远不要这样做。)请参阅下面评论中关于在不同操作系统上不同版本的 GCC 中观察到的行为的讨论。(我不知道版本 4.5.3 仅给出警告而不是错误这一事实是否表明这将始终是“安全的”,因为如果您编译,指针将在当前范围内的任何地方都有效使用特定版本的 GCC,但我不会指望它。)
这是我使用的代码(根据 Jonathan Leffler 的建议进行了修改):
#include <stdio.h>
class Class {
public:
int a;
int b;
Class(int va, int vb){a = va; b = vb;}
};
int main(){
Class *p = &Class(1, 2);
Class *q = &Class(3, 4);
printf("%p: %d,%d\n", (void *)p, p->a, p->b);
printf("%p: %d,%d\n", (void *)q, q->a, q->b);
}
当使用 GCC 4.5.3 编译并运行(在 Windows 7 SP1 上)时,此代码打印:
0x28ac28: 1,2
0x28ac30: 3,4
当使用 GCC 4.7.1 编译并运行(在 Mac OS X 10.8.3 上)时,它打印:
0x7fff51cd04c0: 0,0
0x7fff51cd04d0: 1372390648,32767
在任何情况下,我都不确定您为什么不只是正常声明变量并&v
在需要“类似指针”的任何地方使用(例如,在需要指针作为参数的函数中)。