Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在运行时确定参数的性质_C++_Memory_New Operator - Fatal编程技术网

C++ 在运行时确定参数的性质

C++ 在运行时确定参数的性质,c++,memory,new-operator,C++,Memory,New Operator,我有一个函数 void fname(char* Ptr) { ... } 我想知道在这个函数中,这个指针Ptr是使用newchar[]保存动态分配内存的地址,还是调用函数中本地分配内存的地址。有什么办法可以确定吗?我认为在这里没有帮助 简单的回答是:不,你不能。您无法知道Ptr是否是指向单个char的指针、静态分配数组的开头、指向单个动态分配char的指针或数组的开头 如果您真的想,您可以尝试这样的重载: template <std::size_t N> void fnam

我有一个函数

void fname(char* Ptr)
{
    ...
}

我想知道在这个函数中,这个指针
Ptr
是使用
newchar[]
保存动态分配内存的地址,还是调用函数中本地分配内存的地址。有什么办法可以确定吗?我认为
在这里没有帮助

简单的回答是:不,你不能。您无法知道
Ptr
是否是指向单个
char
的指针、静态分配数组的开头、指向单个动态分配
char
的指针或数组的开头

如果您真的想,您可以尝试这样的重载:

template <std::size_t N>
void fname(char Ptr[N])
{
   // ...
}
模板
void fname(char Ptr[N])
{
// ...
}
当传递一个静态分配的数组时,它将匹配,而当处理动态分配的内存或指向单个
char
的指针时,将选择第一个版本


(但请注意,在存在模板的情况下,函数重载规则有点复杂——特别是,如果匹配,则首选非模板函数。因此,如果采用这种方法,可能需要使原始函数采用“伪”模板参数。)

一种方法是让您自己的
操作员拥有新的
功能,并跟踪分配的所有内容,这样您就可以询问分配库给定的地址是否是它分配的地址。然后,自定义分配器只调用标准分配器来实际执行分配

另一种方法(凌乱且细节高度依赖操作系统)可能是检查虚拟内存中的进程布局,从而确定哪些地址指的是内存的哪些区域

您可以通过实际管理自己的内存池来结合这些想法。因此,如果您获得一大块具有已知地址边界的系统内存,并将其用于所有
'd内存,您只需检查给定范围内的地址即可回答您的问题

然而:如果这个问题是这样做的唯一目的,那么这些想法中的任何一个都是大量的工作,是不合适的

话虽如此,如果你真的想实现一些东西,你需要仔细研究所有可能生成地址的方法

例如(我肯定错过了一些):

  • 堆叠
  • 从纽约回来
  • 里面有一件从新买回来的东西
  • 从新的返回,但已删除(希望不是,但这就是我们需要诊断的原因)
  • 静态分配
  • 静态恒定存储器
  • 命令行参数/环境
  • 代码地址
现在,暂时忽略所有这些,并假设这是出于某种调试目的而不是系统设计,您可能可以尝试这种方法:

这是丑陋的、不可靠的、不受标准保障的等等,但可能有效

char* firstStack  = 0;

bool isOnStack(const void* p)
{
    char* check =(char*)p;
    char * here = (char*)&check;
    int a = firstStack - check;
    int b = check - here;
    return (a*b > 0);
}

void g(const char* p)
{
    bool onStack = isOnStack(p);
    std::cout << p  << (onStack ? "" : " not" ) << " on stack " << std::endl;
}

void f()
{
    char stuff[1024] = "Hello";
    g(stuff);
}

void h()
{
    char* nonsense = new char[1024];
    strcpy(nonsense, "World");
    g(nonsense);
    delete [] nonsense;
}

int main()
{
    int var = 0;
    firstStack = (char*)&var;
    f();
    h();    
}
char*firstStack=0;
bool isOnStack(const void*p)
{
字符*检查=(字符*)p;
char*here=(char*)&check;
int a=第一堆栈-检查;
int b=检查-此处;
返回(a*b>0);
}
空g(常量字符*p)
{
bool-onStack=isOnStack(p);

std::cout在vc++中有一个断言_CrtIsMemoryBlock(),可用于检查指针是否从堆中分配。这仅在使用调试堆时有效,但如果您只是想添加一些“仅调试”断言,则可以使用。过去在Windows下,此方法对我很有效

然而,对于Linux,我不知道有这样的等价物


或者,您可以使用内联汇编程序块来尝试确定它是否是堆栈地址。这将取决于硬件,因为它不仅严重依赖于处理器类型,还严重依赖于所使用的内存模型(平面地址模型与分段等)。最好避免这种方法。

我看到的一种可能性是通过使用
delete[]
运算符。如果指针不包含动态分配内存的地址,那么
delete[]Ptr
应该会产生运行时错误。它有什么好处吗?@Prakash No,
delete[]
不会引发异常(在C++11中,它被显式地标记为
noexcept
)。试图在静态分配的东西上使用它,充其量是未定义的行为,可能只是崩溃。