5

我见过至少 5 个以这种方式返回指针的 C++ 教程网站:

int* somefunction(){
    int x = 5;
    int *result = &x;
    return result;
}

这不是一个非常非常糟糕的主意吗?我的逻辑告诉我返回的指针的值可以随时被覆盖。我宁愿认为这将是正确的解决方案:

int* somefuntion(){
    int x = 5;
    int* result = new int;
    *(result) = x;
    return result;
}

然后离开调用函数来删除指针。还是我错了?

4

6 回答 6

8

你对这个问题的直觉是正确的——结果就是 UB。但是,您提出的解决方案很糟糕。“让调用者删除它”非常容易出错且不可取。相反,将它返回到某个拥有的类中,该类正确地封装了它的预期用途——最好是std::unique_ptr<int>

于 2012-06-30T15:37:32.830 回答
6

是的,第一个选项将返回一个悬空指针,并导致未定义的行为。您的第二个选项是正确的,尽管您可以只写:

int* somefuntion(){
    return new int(5);
}

或者static在方法中有一个变量并返回它的地址。

于 2012-06-30T15:35:14.443 回答
3

您的问题将几个不同的问题合二为一。实际上,这里的主要问题是您是否真的需要这种混合物。

本身没有“返回指针”之类的东西。您不会仅仅因为您想“返回指针”而“返回指针”。返回指针是出于某种特定原因而完成的,该原因将决定它是如何完成的以及需要做什么才能确保它正常工作。

您的原始示例并没有真正说明这一点,因为在您的原始示例中根本没有有意义的理由返回一个指针。看起来您可以简单地返回一个int.

例如,在许多情况下,您会希望返回一个指针,因为它是指向动态分配对象的指针,即其生命周期不受语言范围规则约束的对象。请注意,这种情况下的随意关系在相反的方向上起作用:您需要一个动态对象 -> 您必须返回一个指针。那样,而不是反过来。在您的示例中,您似乎向后使用它:我想返回一个指针-> 我必须动态分配对象。后一种推理从根本上是有缺陷的,尽管人们可能会看到它的使用频率比预期的要高。

如果你真的需要一个动态分配的对象(正如我上面所说,主要原因是要覆盖语言的基于作用域的生命周期规则),那么内存所有权问题就会成为问题。为了知道何时可以/必须释放此内存以及谁必须释放它,您必须实现独占(随时指定一个所有者)或共享(如引用计数)所有权方案。它可以使用原始指针来完成,但更好的想法是使用库提供的各种智能指针类。

但在许多情况下,您还可以返回指向非动态对象(静态或自动)的指针,假设这些指针的生命周期与它们指向的对象的生命周期相同或更短,这完全没问题。

换句话说,决定返回指针的原因在 C 和 C++ 之间并没有真正的不同。它与设计/意图相关而不是与语言相关。只是 C++ 为您提供了更多工具,让您在决定返回指针后更轻松。(这有时会促使 C++ 程序员过度使用隐藏的指针)。

在任何情况下,这又是您尝试实现什么功能的问题。一旦知道了这一点,您就可以对是否应该“返回指针”做出正确的决定。如果你最终决定返回一个指针,它将帮助你选择合适的返回方法。这就是它的工作原理。试图向后考虑它(“我只想返回一个指针,但我还没有真正的理由”)只会产生学术上无用的答案,每个答案都可以在某些情况下被证明是“错误的”具体情况。

于 2012-06-30T15:40:48.163 回答
3

是的,第一个示例不好,因为您将返回一个指向内存的指针,系统可能会将其重新用于其他用途。第二个示例更好,但仍然存在泄漏内存的风险,因为 somefunction 的调用者不清楚删除指向的内存是他们的责任。

像这样的东西可能会更好:

std::unique_ptr<int> somefunction(){
    int x = 5;
    std::unique_ptr<int> result( new int );
    *result = x;
    return result;
}

这样,unique_ptr 将负责删除新的内存,并有助于消除潜在的内存泄漏。

于 2012-06-30T15:44:12.063 回答
1

正如您所怀疑和其他人所澄清的那样,第一种方法显然是错误的。尽管 C++ 是一种系统语言,并且在某些情况下您可能希望这样做(在大多数系统上,它将返回堆栈上特定的相对位置),但它几乎永远不会正确。第二种方法要理智得多。

但是,在 C++ 中不应该鼓励这两种方法。C++ 的要点之一是您现在拥有引用和异常,而不仅仅是 C 的指针。因此,您要做的是返回一个引用,并允许 new 在内存分配失败时将异常抛出堆栈。

于 2012-06-30T15:44:33.953 回答
0

不要忘记在调用您的方法后删除指针,这是正确的。

于 2012-06-30T15:37:23.750 回答