指针指向动态内存还是静态分配的内存的判断方法

4

有没有办法知道指针是指向动态分配的内存还是静态分配的内存?

数组作为指针传递给函数。

void func (int* p)
{
  if( p )
  {
    cout << p[0] << p[1] ;
   ...
   // func has a responsibility to deallocate what p is pointing
  }
}

int main()
{
  int a[] = {10, 20, 30, 50};
  func(a);
  ...
  return 0;
}

如果将所有权转移给函数进行释放。 那么,函数 p 如何知道 'p' 是否指向动态分配的内存还是静态分配的内存?

5
你无法知道这件事。 - πάντα ῥεῖ
2
请在C和C++中选择一个。这两种语言是不同的。 - fuz
1
你为什么认为“func有责任释放p所指向的内存”? - artm
如果您想转移所有权,可以使用智能指针。 - Jarod42
是的。在你的函数中注释掉你传递了一个动态分配的数组! - haccks
6个回答

4

你无法知道这个。这是由你的函数定义决定的。建议使用智能指针,或者在函数文档中明确说明它接管了传递对象或数组的所有权。


2

没有一种通用的方法可以确定指针是指向动态分配的内存还是静态分配的内存。可能可以通过仔细检查指针是否指向已加载到程序中的任何二进制文件或共享库的数据或bss段之一来推断此信息。即使如此,静态和动态分配内存之间的界线仍然模糊:您认为作为共享库一部分的内存在后面加载时是动态的还是静态的?


1
首先,使用函数需要适当的参数是调用者的责任,而编写者则需要明确指出该函数会尝试释放传递的指针。
其次,将算法函数管理内存不是一个好的实践。主要原因是您可能希望在输入的子集上使用它。例如,如果您计算数组的总和,则可能希望能够计算从索引3开始的子数组的总和。
管理内存是调用者的职责,而不是你的职责。只需不要在执行其他操作的函数中添加任何释放处理。
无论如何,您都可以检测地址是否在堆栈上,参见1。但请注意,不在堆栈上并不意味着它是在堆上分配的,可能指向某些静态数据,比如字符串常量。

0

你无法判断。

你应该在“相同类型的位置”释放内存。广义上来说,这意味着如果调用函数的人分配了内存,则该调用者应释放它。同样,如果您提供了一个函数来分配内存,则应提供另一个函数来释放它。

有些人喜欢在函数中分配内存,并使调用者负责释放它。但是,这可能会引起问题,特别是如果函数与调用者分别编译,比如在 dll 或共享对象中。

你要提出的建议:在调用者中分配内存后,在函数中删除内存是最糟糕的情况。 不要这样做


0

不仅你无法真正了解它,甚至无法判断指针是否有效。

int* x = 0xDEADBEEF;

显然,大多数情况下指针甚至没有指向有效的内存地址。

但并非一切都失去了。您可以使用各种技巧来至少部分实现此目标。其中一些包括:

  1. 创建一个内存池,并强制从中分配任何动态内容。然后,通过简单的指针算术运算,您可以找出内存地址是否存在。
  2. 重载全局的newdelete。除非您的某些类重载了newdelete运算符,否则您可以捕获大多数动态分配。如果您正在使用malloc,则此方法将无效。
  3. 如果您在Windows上,并且是WinAPI专家,则可以尝试挂钩HeapAlloc,从而跟踪一些内存地址。

-1
//***************************************************************//
//******************  try something like this  ******************//
//***************************************************************//

#include <stdlib.h>
#include <stdio.h>

// define one of these
// define LINUX
#define MACOS
// #define WINDOWS

#if defined LINUX || defined WINDOWS
#include <malloc.h>
#endif
#ifdef MACOS
#include <malloc/malloc.h>
#endif


// prototypes
int     freeable(void *ptr);
void    safe_free(void *ptr, const char *function, int line);


inline int freeable(void *ptr)
{
    size_t    sz;
#ifdef MACOS
    sz = malloc_size(ptr);
#endif
#ifdef LINUX
    sz = malloc_usable_size(ptr);
#endif
#ifdef WINDOWS
    sz = _msize(ptr);
#endif

    // fprintf(stderr, "freeable bytes = %ld\n", sz);
    if (sz)
        return(TRUE);

    return(FALSE);
}


void    safe_free(void *ptr, const char *function, int line)
{
    if (freeable(ptr) == FALSE) {
        if (ptr == NULL)
            fprintf(stderr, "%s(): Attempting to free NULL object [called from function %s(), line %d]\n\n", __FUNCTION__, function, line);
        else
            fprintf(stderr, "%s(): Attempting to free unallocated, statically allocated, or previously freed object [called from function %s(), line %d]\n\n", __FUNCTION__, function, line);
        return;
    }

    free(ptr);

    fprintf(stderr, "%s(): Successfully freed object [called from function %s(), line %d]\n\n", __FUNCTION__, function, line);

    return;
}


int main(int argc, char *argv[])
{
    void    *ptr;
    size_t  sz;

    ptr = NULL;
    fprintf(stderr, "\nfree NULL ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    ptr = (void *) "string";
    fprintf(stderr, "free static string:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    ptr = (void *) 0x0123456789BCDEF;
    fprintf(stderr, "free unallocated ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    ptr = (void *) malloc(10);
    fprintf(stderr, "free allocated ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    fprintf(stderr, "free previously freed ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    return(0);
}

这并不总是有效的。safe_free((int*)malloc(1024)-1) 对我来说会崩溃:https://gcc.godbolt.org/z/j35fvcdhj - HolyBlackCat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接