0

Here's my problem: I read here on StackOverflow that it is unsafe sometimes to return pointers to local variables from a function. For example:

#include<iostream>

using namespace std;

int *foo(void) {
    int x[] = {1,2,3};
    return x;
}

int main() {
    int *numbers;
    numbers = foo();
    return 0;
}

I'd like to know if this is unsafe, considering that x being a local array, the memory could be unallocated, what's the better way to achieve the same result?

4

6 回答 6

10

我在 StackOverflow 上读到,有时从函数返回指向局部变量的指针是不安全的。

返回指向局部变量的指针总是不安全的确实这样做是错误的,使用这个指针会导致未定义的行为。另见这篇很棒的帖子

如果要将数据返回到调用范围,可以使用std::vector作为副本:

std::vector<int> foo(void){
  std::vector<int> x = {1,2,3}; // using C++11 initializer list
  return x;
}

如果它是一个固定长度的数组(总是大小为 3),你可以使用std::array代替。


根据您的要求,您还可以使用静态变量。也就是说,变量永远不会超出范围,您可以通过引用(或通过指针)安全地返回它。请注意,您只有一份副本。如果您修改它,它将保持修改状态。(const &如果它是只读的,那就做吧。)

std::vector<int>& foo(void) {
  // this is only instantiated once when the function is first called
  static std::vector<int> x = {1,2,3}; 
  return x;
}
于 2012-07-02T10:40:08.103 回答
0

返回指向局部变量的指针永远是不安全的(实际上这是未定义的行为)。对于大多数实现,它们位于堆栈中,因此可以在使用指针时覆盖它。

您可以返回一个动态分配的数组:

int* foo() { int* x = new int[3]; ..}

当然,您需要手动删除指针,这使得编写健壮、安全的代码变得很困难。因此,通常最好使用向量:

std::vector<int> foo() { 
   std::vector<int> x;
   x.push_back(1); 
   x.push_back(2); 
   x.push_back(3);
   return x;
}

如果您使用 c++11,您可以使用初始化列表来填充向量,从而使代码更好:

std::vector<int> foo() { std::vector<int> x = {1,2,3};  return x; }

C++11 具有移动语义,这意味着在这种情况下,按值返回向量几乎不会花费任何性能。对于 C++03,如果性能至关重要,您可以为函数提供一个指向向量的引用/指针作为参数并填充:

void foo(std::vector<int>& x) {x.clear(); x.push_back(1); ...}
于 2012-07-02T10:44:28.113 回答
0

首先int x = {1,2,3}是语法错误。它应该是int x[] = {1,2,3};

这是未定义的行为。因为自动数组在其定义的块内有生命周期,即在foo()函数内。因此,无论何时您从foo()存储中返回,x都不再保证为您保留。因此,如果您通过指针访问该位置,则行为未定义。

为了达到同样的效果,动态分配内存。

int *foo(void){
int x[] = {1,2,3}, *x_to_return;
x_to_return = new int [sizeof (x)/sizeof(x[0])];
memcpy (x_to_return, x, sizeof (x));
return x_to_return;
}

基本上,您需要做的是使用 动态分配存储new,将数据复制到分配的内存块(其基础)new并将该内存地址返回给调用者。

完成使用后不要忘记释放分配的内存,否则您的代码会出现内存泄漏。

还有一点需要注意,如果你有这样的声明,static int x[] = {1,2,3};你可以返回 的地址x,因为在这种情况下,生命周期x是整个程序运行时。

由于您的问题被标记为 c++ you should use vector,请查看 moooeeeep 的答案。

于 2012-07-02T10:40:00.897 回答
0

返回指向该数组的指针是不安全的(或者说是错误的),因为当函数返回时它不再存在。内存不仅可以被释放,而且被释放。
请注意,它可能仍然会意外工作,但老实说,这会比它不工作更糟糕(因为它是不可预测的并且无法调试)。永远不要尝试“但它似乎有效”的事情,即使它们似乎有效。

这与返回指针或引用相同,但const引用是一个例外。引用使被引用对象在const其自己的生命周期内保持活动状态。

static如果您想返回一个指针,动态分配或制作对象将是选项。或者,只是按值返回一个临时对象,依靠编译器将其 RVO。

于 2012-07-02T10:40:16.930 回答
0

您可以:

  1. 将 x 声明为static
  2. 将 x 声明为pointer
于 2012-07-02T10:41:46.917 回答
-1

是的,这是不安全的,因为数组是在堆栈上分配的,因此当函数返回时它将被释放。

与其在函数内部分配数组,不如在外部创建它并将指向它的指针传递给函数。这只是一个例子:

#include<iostream>
using namespace std;

void foo(int numbers[]){
    numbers[0] = 1;
    numbers[1] = 2;
    numbers[2] = 3;
}

int main(int args, char**argv) {
    int numbers[3];
    foo(numbers);
    cout << numbers[0] << numbers[1] << numbers[2];
    return 0;
}

这将打印“123”。

于 2012-07-02T10:54:42.023 回答