返回指针的最佳方式

Best way of returning a pointer

本文关键字:方式 最佳 指针 返回      更新时间:2023-10-16

我见过至少 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;
}

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

你对问题的直觉是正确的 - UB 就是结果。但是,您提出的解决方案是 le 坏的。"让调用者删除它"非常容易出错,也是不可取的。相反,在某个正确封装其预期用途的拥有类中返回它 - 最好是std::unique_ptr<int>

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

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

或者在方法中包含一个static变量并返回其地址。

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

这样的东西可能会更好:

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

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

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

本身没有"返回指针"这样的事情。您不会仅仅因为要"返回指针"而"返回指针"。返回指针是出于某种特定原因而完成的,该原因将指示如何完成以及需要做什么以确保其正常工作。

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

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

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

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

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

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

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

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

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