范围、数组和堆
Posted
技术标签:
【中文标题】范围、数组和堆【英文标题】:Scope, arrays, and the heap 【发布时间】:2009-07-10 06:26:23 【问题描述】:所以,我有这个数组。它需要在此函数范围之外访问。我一直在将指向它的指针拍成一对,然后放入双端队列。但是一旦我超出了作用域,本地堆栈就消失了,数组无效了,我只是得到了一个无用的指针,对吧?
所以我试图把这个数组放到超越范围的堆上,它会一直保留在那里,直到我以后删除它。但我在让这个工作时遇到问题。现在 g++ 正在吐出关于从 'int' 到 'int*' 的无效转换的错误。
void randomFunction(int x, int y, int width, int height)
int **blah[4] = x, y, width, height;
std::pair <foobar*, int* > tempPair (foobar1, blah);
randomDeque.push_front(tempPair);
我也试过这样初始化它:
int *blah[4] = new int[4];
...它说数组必须用大括号括起来的初始化程序进行初始化。
我真的不习惯使用指针。我做错了什么?
【问题讨论】:
【参考方案1】:有两个问题。首先,确实,您对指针/数组感到困惑:
int a[4]; // this is an array of 4 integers, a is the name of the array
int *a[4]; // This is an array of 4 *pointers* to int
所以你的声明:
int **blah[4];
定义一个由 4 个指向指针数组的指针组成的数组。也许你对以下事实感到困惑(我知道我在学习 C 时就是这样)。如果你声明一个变量:
int *a;
这是一个指向整数的指针的声明。但是如果你有一个变量 a 是一个指针,你可以使用 *a 得到它指向的东西(这里是一个整数):
*a = 1; // a is a pointer (i.e. an address), *a is the value pointed to by a.
所以 * in 声明用于声明指针,而 * in 语句用于引用值。
但是您的第二个问题与指针本身无关。它是关于资源管理(内存是一个,但文件,锁是其他)。当超出范围时,在堆栈上分配的任何内容都不再存在。在纯 C 中,您实际上只有一个解决方案:使用 malloc 在堆上分配,然后确保释放。所以你会做这样的事情:
// foo is a struct
foo *init_foo()
foo* tmp;
tmp = malloc(sizeof(*tmp));
// initialize tmp
return tmp;
然后,您将使用另一个功能对其进行清理:
foo *a;
a = init_foo();
// do stuff
clean_foo(a);
示例:FILE* 句柄和 fopen/fclose(除了分配东西,还有一些与操作系统相关的东西来处理文件)。另一种解决方案是使用 alloca,它不是标准 C,但被许多工具链支持。
在 C++ 中,您可以使用智能指针,例如使用引用计数来进行资源管理。我对 C++ 不太熟悉,我相信人们会参与其中。引用计数的想法是它仍然具有自动指针的一些优点(您不必自己调用 delete,这对于不平凡的项目非常容易出错),但不是纯粹基于范围的。一种基于引用计数的智能指针是 boost 中的 shared_ptr。
【讨论】:
【参考方案2】:整个概念对我来说看起来很奇怪。如果您在堆栈上声明数组,它将不存在于您的函数范围之外。如果您使用“新”分配它 - 请确保在某个时候“删除”它,否则会导致 内存泄漏! 带有“新”的正确代码是:
int *blah = new int[4];
...
// don't forget to:
delete [] blah;
【讨论】:
【参考方案3】:我不确定我是否做对了你想做的事,但如果你想返回一个在 randomFunction
返回后有效的 int 数组的引用,那么使用 Boost 是一个好方法:
#include <boost/shared_ptr.hpp>
#include <vector>
boost::shared_ptr<std::vector<int> > randomFunction(int x, int y, int width, int height)
boost::shared_ptr<std::vector<int> > blahPtr(new std::vector<int>(4));
(*blahPtr)[0] = x;
(*blahPtr)[1] = y;
(*blahPtr)[2] = width;
(*blahPtr)[3] = height;
return blahPtr;
您不必记住 delete
ing blahPtr
-- 当它的所有副本超出范围时,Boost 将自动删除您的 std::vector
对象,并且 C++ 标准库将删除底层数组。
【讨论】:
【参考方案4】:看起来你想要一个 4x4 数组,在这种情况下你应该像这样创建它(我头脑中的未经测试的代码):
int **blah = new int* [4];
for(int i = 0; i < 4; ++i)
*blah[i] = new int[4];
或者,您可以创建一维数组并将其视为二维数组:
int *blah = new int[16];
#define ELEM(x,y) w*4+h
blah[ELEM(1,1)] = 123;
【讨论】:
您突出显示代码,然后按 ctrl-k 或 代码示例 按钮来格式化它。 谢谢尼克 我很着急,找不到明显的方法 但是...我不想要 4x4 数组。 ;-) 对不起,我假设你这样做了,因为你使用的是 ** ;)以上是关于范围、数组和堆的主要内容,如果未能解决你的问题,请参考以下文章
c_cpp 使用在堆栈上声明的数组(int myArray [3])和堆上的数组(int * myArray = new int [size]