返回指向函数声明的数据的指针

我知道这不起作用,因为变量x在函数返回时被销毁:

int* myFunction() { int x = 4; return &x; } 

那么如何正确地返回指向我在函数中创建的东西的指针,以及我需要注意什么? 如何避免内存泄漏?

我也用过malloc:

 int* myFunction2() { int* x = (int*)malloc(sizeof int); *x = 4; return x; } 

你是如何正确地做到这一点的 – 在C和C ++中?

对于C ++,您可以使用智能指针来强制执行所有权转移。 auto_ptrboost::shared_ptr是不错的选择。

你的第二种方法是正确的。 您只需要清楚地记录调用者“拥有”结果指针,并负责释放它。

由于这种额外的复杂性,很少为像“int”这样的“小”类型执行此操作,尽管我假设您在这里仅使用了一个int作为示例。

有些人还希望将指向已分配对象的指针作为参数,而不是在内部分配对象。 这使得更清楚的是调用者负责释放对象(因为他们首先分配它),但是使调用站点更加冗长,所以这是一个权衡。

对于C ++,在许多情况下,只需按值返回。 即使在较大物体的情况下, RVO也经常避免不必要的复制。

一种可能性是将函数传递给指针:

 void computeFoo(int *dest) { *dest = 4; } 

这很好,因为你可以使用自动变量这样的函数:

 int foo; computeFoo(&foo); 

使用这种方法,您还可以将内存管理保留在代码的相同部分,即。 你不能错过malloc只是因为它发生在函数内部的某个地方:

 // Compare this: int *foo = malloc(…); computeFoo(foo); free(foo); // With the following: int *foo = computeFoo(); free(foo); 

在第二种情况下,你更容易忘记免费,因为你没有看到malloc。 这通常至少部分通过约定来解决,例如:“如果函数名称以XY开头,则表示您拥有它返回的数据。”

返回指向“function”变量的指针的有趣角落情况是声明变量static:

 int* computeFoo() { static int foo = 4; return &foo; } 

当然这对于正常编程来说是邪恶的,但它有朝一日可能会派上用场。

C ++方法可以避免内存泄漏。 (至少在忽略函数输出时)

 std::auto_ptr myFunction() { std::auto_ptr result(new int(4)); return result; } 

然后叫它:

 std::auto_ptr myFunctionResult = myFunction(); 

编辑:正如乔尔所指出的那样。 std :: auto_ptr有它自己的缺点,通常应该避免。 而不是std :: auto_ptr你可以使用boost :: shared_ptr(std :: tr1 :: shared_ptr)。

 boost::shared_ptr myFunction() { boost::shared_ptr result(new int(5)); return result; } 

或者当使用C ++ 0x符合编译器时您可以使用std :: unique_ptr。

 std::tr1::unique_ptr myFunction() { std::tr1::unique_ptr result(new int(5)); return result; } 

主要区别在于:

  • shared_ptr允许多个shared_ptr实例指向同一个RAW指针。 它使用引用计数机制来确保只要存在至少一个shared_ptr实例就不会释放内存。

  • unique_ptr只允许它的一个实例持有指针,但与auto_ptr不同,它具有真正的移动语义。

在C ++中,您应该使用new

  int * myFunction()
 {
     int blah = 4;
     return new int(blah);
 } 

要摆脱它,使用删除:

  int main(void)
 {
     int * myInt = myFunction();
     // 做东西
    删除myInt;
 } 

请注意,我在使用new调用int的复制构造函数,以便将值“4”复制到堆内存中。 获取指向堆栈上某些东西的指针的唯一方法是通过正确调用new将其复制到堆上。

编辑:如另一个答案中所述,您还需要记录稍后调用者需要释放指针。 否则您可能会发生内存泄漏。

还有另一种方法 – 声明x静态。 在这种情况下,它将位于数据段中,而不是位于堆栈上,因此在程序运行时期间它是可用的(并且是持久的)。

 int *myFunction(void) { static int x = 4; return &x; } 

请注意,只有在第一次调用myFunction才会执行赋值x=4

 int *foo = myFunction(); // foo is 4 *foo = 10; // foo is 10 *foo = myFunction(); // foo is 10 

NB! 使用函数范围静态变量不是踏板安全技术。

您的第二个代码段是正确的。

为了帮助避免内存泄漏,我让编码约定帮助我。

xxxCreate()将为xxx分配内存并初始化它。 xxxDelete()将破坏/损坏xxx并释放它。

xxxInit()将初始化xxx(永不分配)xxxDestroy()将破坏/损坏xxx(永不免费)

另外,一旦我将代码添加到create / init / malloc,我就会尝试添加代码来删除/销毁/释放。 它并不完美,但我发现它可以帮助我区分需要释放的物品和不需要物品的物品,以及减少我以后忘记释放物品的可能性。

Boost或TR1共享指针通常是要走的路。 它避免了复制开销,并为您提供半自动删除。 所以你的function应该是这样的:

 boost::shared_ptr myFunction2() { boost::shared_ptr x = new int; *x = 4; return x; } 

另一种选择就是允许复制。 如果对象很小(比如这个),那也不错,或者你可以安排在return语句中创建对象。 如果在return语句中创建对象,编译器通常会优化副本。

我会尝试这样的事情:

 int myFunction2b( int * px ) { if( px ) { *px = 4; return 1; } // Choice 1: Assert or Report Error // Choice 2: Allocate memory for x. Caller has to be written accordingly. // My choice is 1 assert( 0 && "Argument is NULL pointer" ); return 0; } 

你问的是如何正确返回一个指针。 这是错误的问题,因为你应该做的是使用智能指针而不是原始指针。 scoped_ptr和shared_ptr(在boost和tr1中可用)是很好的指针(例如这里和这里 )

如果你需要原始指针(例如传递给C函数), get()方法将提供它。

如果你必须创建原始指针,例如作业,那么你可以在函数中使用malloc() (就像你做的那样)或new ,并希望你记得去除内存(分别通过free()delete )或者,在一个稍微不太可能泄密的习语中,你可以用new创建指针,将它传递给一个函数,并在你完成它时用delete删除 。 但是,再次使用智能指针。