2

考虑一个返回 a 的函数,Type*因此它看起来可以Type在其定义中分配 a ,但您无法确定(有很多函数,您没有时间阅读它们的定义)。

你怎么知道你是否应该删除返回的指针?例如,这是类型:

struct MyStruct
{
    MyStruct(void) { cout << "Created.\n"; }
    ~MyStruct(void) { cout << "Deleted.\n"; }
};

这是功能:

MyStruct* Func1(void)
{
    return (new MyStruct());
}

Func1 分配了一个指针,您应该稍后取消分配它。但也许定义是别的东西,指针不应该是deleted。

我的问题是:你怎么知道是否删除指针?例如:也许指针是静态的?

MyStruct* Func2(void)
{
    static MyStruct* ms = &MyStruct();
    return ms;
}

取消分配这个指针会使整个程序崩溃。

提前致谢。

4

4 回答 4

8

无法以编程方式对此进行检查。1 作为程序员,您需要了解哪些需要删除,哪些不需要。

更一般地说,这是在 C++ 中传递原始指针经常不受欢迎的原因之一。 智能指针通常用于管理动态分配的内存。


1. 至少,不是以一种强大的平台独立方式。

于 2012-07-21T09:59:16.210 回答
7

你怎么知道你是否应该删除返回的指针?

你不能,这就是为什么使用原始指针来管理内存是一个非常糟糕的主意的原因之一。如果一个对象需要删除,那么应该总是使用智能指针自动完成。

这还有一个好处是,一旦你完成了动态对象,它就会被删除,即使抛出异常也是如此。

std::unique_ptr<MyStruct> Func1()
{
    return std::unique_ptr<MyStruct>(new MyStruct);
}

void do_something()
{
    auto thing = Func1();
    do_something_with(thing);

    // The object is automatically deleted here
    // even if the function threw an exception.
}

如果您被迫使用设计不佳的库,其函数返回的指针可能需要删除,也可能不需要删除,那么您唯一的选择就是阅读文档或找到更好的库。立即将任何需要删除的指针分配给智能指针是一个好主意,因此您至少具有异常安全性。

于 2012-07-21T10:09:00.893 回答
1

事实:如果您没有时间阅读 API 文档,那么您将遇到错误。

归结为函数总是做出很多假设的原则,所有假设都由不同的机制强制执行:

  1. 有些是由编译器自动执行的,通常是通过类型。例如,如果函数必须假设它可以写入某个参数,那么它的类型将是非常量的,并且传递一个 const 参数将导致编译器错误。这是防止错误的最佳方法。返回智能指针是一种为指针所有权提供编译器强制执行的方法,因此不需要文档。这就是为什么我们更喜欢模板或基类而不是void*.
  2. 有些是通过惯例或惯例暗示的。这再次意味着您不需要阅读文档来遵守函数的假设,因为这对于任何有能力的程序员来说都应该是显而易见的。例如,如果 C++ 函数请求网格的行或列,您可以期望它是从 0 开始的。这是约定。或者对于您的情况,如果函数返回引用,则按照惯例,调用者不应删除该对象。
  3. 除了通过文档之外,还有许多假设根本无法执行。例如,您无法知道函数是否会进行边界检查或接受 NULL 指针。作为 API 开发人员,您应该尽可能避免这种情况,但在面对它时,您不能忽略文档。

作为 C++ 开发人员,我们尽可能多地使用 #1,但不能完全避免其他的。

于 2012-07-21T10:32:29.190 回答
0

我完全同意 Mike 和 Oli 的观点,只补充一点:如果库写得很好,那么可能有一些标准用来指出你何时是函数返回的指针的所有者(意味着你必须删除它) . 这可以通过命名来完成,或者该函数属于某个类/命名空间。在这种情况下,您可以避免阅读每个函数的定义。

于 2012-07-21T10:22:31.323 回答