删除参考

时间:2010-07-13 03:29:02

标签: c++

这有效吗?一种可接受的做法?

typedef vector<int> intArray;

intArray& createArray()
{
    intArray *arr = new intArray(10000, 0);

    return(*arr);
}


int main(int argc, char *argv[])
{

    intArray& array = createArray();

    //..........

    delete &array;

    return 0;
}

6 个答案:

答案 0 :(得分:52)

代码的行为将是您的预期行为。现在,问题在于,虽然您可能认为编程是关于为编译器编写要处理的内容,但是编写其他程序员(或将来的某些程序员)能够理解并能够维护的东西也同样重要。在许多情况下,您提供的代码等同于使用编译器的指针,但对于其他程序员来说,它只是潜在的错误来源。

引用意味着是在其他地方管理的对象的别名。一般来说,当遇到delete &ref时,人们会感到惊讶,并且在大多数情况下,程序员不会期望必须对引用的地址执行delete,因此将来可能会有人去调用该函数忘记删除,你将有内存泄漏。

在大多数情况下,通过使用智能指针可以更好地管理内存(如果您不能使用其他高级结构,如std::vector)。通过将指针隐藏在引用之后,您将更难在返回的引用上使用智能指针,因此您无法帮助用户更难以使用您的界面。

最后,引用的好处在于,当您在代码中读取它们时,知道对象的生命周期在其他地方进行管理,您不必担心它。通过使用引用而不是指针,您基本上会回到单个解决方案(以前仅在C指针中),并且必须特别注意所有引用以确定是否必须在那里管理内存,而不是意味着更多的努力,有更多的时间来考虑内存管理,而不必担心实际问题得到解决 - 由于异常代码的额外压力,人们越来越习惯用指针查找内存泄漏,并期望没有引用内容。

简而言之:通过引用保存的内存会隐藏用户处理内存的要求,并使其更难以正确执行。

答案 1 :(得分:13)

是的,我认为它会起作用。但是如果我在我工作的任何代码中看到类似的东西,我会把它撕掉并立即重构。

如果要返回已分配的对象,请使用指针。 请!

答案 2 :(得分:12)

这是有效的...但我不明白为什么你想要这样做。这不是例外安全,std::vector无论如何都会为你管理内存。为什么new呢?

编辑:如果要从函数返回新内存,则应返回指针,以免函数头部的用户爆炸。

答案 3 :(得分:3)

  

这有效吗?

  

可接受的做法?

没有

此代码有几个问题:

  • 设计最不令人惊讶的行为的准则被打破:你返回一些“看起来像”一个对象但必须被客户端代码删除的东西(这应该是一个指针 - 一个引用应该是总是指向的东西到有效的对象)。

  • 您的分配可能会失败。即使您在分配功能中检查结果,您还会返回什么?无效的参考?您是否依赖于为这种情况抛出异常的分配?

作为一个设计原则,考虑创建一个负责管理对象生命周期的RAII对象(在本例中为智能指针)或者在您创建它的同一抽象级别删除指针:

typedef vector<int> intArray;

intArray& createArray()
{
    intArray *arr = new intArray(10000, 0);

    return(*arr);
}

void deleteArray(intArray& object)
{
    delete &object;
}

int main(int argc, char *argv[])
{
    intArray& array = createArray();
    //..........
    deleteArray(array);
    return 0;
}

这种设计改进了编码风格的一致性(分配和释放被隐藏并在同一抽象级别实现)但是通过指针而不是引用仍然更有意义(除非您的对象是动态分配的事实必须仍然是某些设计原因的实现细节。)

答案 4 :(得分:0)

它会起作用,但我担心这是不可接受的做法。在C ++世界中有一个强烈的约定,内存管理是通过指针完成的。您的代码违反了此惯例,并且可能会使任何使用该代码的人绊倒。

似乎你不顾一切地避免从这个函数返回一个原始指针。如果您的问题必须反复检查main中的有效指针,则可以使用引用来处理数组。但是createArray返回一个指针,并确保删除数组的代码也将它作为指针。或者,如果它真的如此简单,只需在main中声明堆栈中的数组并完全放弃该函数。 (在这种情况下,初始化代码可以引用要初始化的数组对象,调用者可以将其堆栈对象传递给init代码。)

答案 5 :(得分:0)

它是有效的,因为编译器可以编译并成功运行。但是,由于

,这种编码实践使得代码对于读者和维护者来说更加困难
  • 手动内存管理
  • 模糊的所有权转移到客户端

但这个问题有一个微妙的问题,那就是效率要求。有时我们不能返回pass-by值,因为对象大小可能太大,如本例中那样笨重(1000 * sizeof(int));是因为;如果我们需要将对象传递给代码的不同部分,我们应该使用指针。但这并不意味着上面的实现是可以接受的,因为对于这种要求,有非常有用的工具,它是智能指针。因此,设计决策取决于程序员,但对于这种特定的实现细节,程序员应该使用可接受的模式,如本例中的智能指针。