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

时间:2010-02-23 18:05:38

标签: c++ c pointers

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

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

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

我也使用了malloc:

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

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

11 个答案:

答案 0 :(得分:7)

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

答案 1 :(得分:6)

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

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

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

答案 2 :(得分:5)

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

答案 3 :(得分:3)

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

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;
}

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

答案 4 :(得分:2)

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

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

然后叫它:

std::auto_ptr<int> myFunctionResult = myFunction();

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

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

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

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

主要区别在于:

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

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

答案 5 :(得分:1)

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

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

要摆脱它,请使用delete:

int main(void)
{
    int *myInt = myFunction();
    // do stuff
    delete myInt;
}

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

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

答案 6 :(得分:1)

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

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

请注意,分配x=4仅在首次拨打myFunction时执行:

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

NB!使用函数范围的静态变量不是一种安全技术。

答案 7 :(得分:1)

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

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

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

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

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

答案 8 :(得分:0)

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

boost::shared_ptr<int> myFunction2()
{
    boost::shared_ptr<int> x = new int; 

    *x = 4; 
    return x;
}

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

答案 9 :(得分:0)

我会尝试这样的事情:

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;

}

答案 10 :(得分:-1)

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

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

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