在C++中编译时确保正确的双指针传递方法

1 c++ parameters pointers compiler-warnings

在过去,我们在软件中遇到了各种内存泄漏.我们发现这些发生的主要原因是我们自己的"免费"方法的使用不正确,这些方法免费提供Queue-Message-Data等.

问题是,在我们最深入的工具函数中,有两种方法可以释放动态分配的内存,具有以下签名:

void free (void *pData);
void free (void **ppData);

两种方法基本上都做同样的事情,除了第二种方法首先取消引用数据.我知道只用这两个中的一个来做所有事情是可能的,但是我们可以说这个软件是多年前设计的,而且现在使用两者都是代码.

当有人实现对这些方法的调用时,问题就出现了:

QueueMessage *pMsg;
pMsg = myQueue.read(...); // dynamically allocates space for the msg and fills it
// Do something
myQueue.free(&pMsg); // << WRONG!

上面的代码应该将指向消息的指针传递给free-method.基本上它可以工作,但由于编译器不知道在这种情况下使用哪个函数,它使用的free(void *pData)方法然后尝试释放指针,而不是指针指向内存.当然,解决方案很简单:或者

myQueue.free(pMsg);

myQueue.free((void**)&pMsg);

两者都有效.既然我已经描述了问题和解决方案,我想知道:有什么方法可以确保使用这些方法的程序员以正确的方式使用它们吗?我已经阅读了VS2005中的标题注释,它们非常有用,但似乎没有做我需要的.如果有一种方法可以在指针的引用传递给第一个方法时产生警告,那将是很好的,所以程序员至少得到一个暗示他的代码有问题的提示.

顺便说一句,我正在使用Microsoft VS2005,如果需要,可以升级到VS2008.它是迁移到VS2005的C++应用程序,因此与.NET兼容.

Mar*_*n B 5

试试模板:

template <class T> void free (T *pData);
template <class T> void free (T **ppData);
Run Code Online (Sandbox Code Playgroud)

这应该给你一个完全匹配的参数类型,因此,编译器应该调用正确的实现.

您可以使用free模板化版本替换原始的void-pointer实现,或者让模板化版本调用原始的void-pointer版本:

template <class T> void free (T *pData)
{
    free(static_cast<void *>(pData));
}

template <class T> void free (T **ppData)
{
    free(static_cast<void **>(ppData));
}
Run Code Online (Sandbox Code Playgroud)

编辑:那么原始版本发生了什么?

重载函数解析的规则相当复杂,但原则上,编译器首先尝试为参数类型找到精确的数学,如果找不到它们,则可以应用各种自动类型转换.

其中一种自动类型转换是任何指针 - 包括指向指针的指针 - 都可以转换为void *指针.但是,没有规则可以将类型指针指针(T **)自动转换为void指针指向(void **).这就是你所有电话的原因free(void *).

当您介绍模板化版本时,这会发生变化.编译器现在可以为您所做的每个调用找到完全匹配 - free(T *)或者free(T **)- 或者这使它能够调用正确的版本.