我知道这不起作用,因为变量x在函数返回时被销毁:
int* myFunction()
{
int x = 4; return &x;
}
那么如何正确地返回指向我在函数中创建的内容的指针,以及我需要注意什么?如何避免内存泄漏?
我也使用了malloc:
int* myFunction2()
{
int* x = (int*)malloc(sizeof int); *x = 4; return x;
}
你如何正确地做到这一点 - 在C和C ++中?
答案 0 :(得分:7)
对于C ++,您可以使用智能指针来强制执行所有权转移。 auto_ptr
或boost::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)