C++可变功能结束
后我有以下代码:C++可变功能结束
void SendRequest(HINTERNET connection, LPCWSTR method, LPCWSTR referer,LPCWSTR path,WINHTTP_STATUS_CALLBACK whCallback){
HINTERNET request;
request=WinHttpOpenRequest(connection, 0,path,0,referer,WINHTTP_DEFAULT_ACCEPT_TYPES,0);
WinHttpSetStatusCallback(request, (WINHTTP_STATUS_CALLBACK)whCallback,WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,0);
REQUEST_CONTEXT cpContext;
WinHttpSendRequest(request,WINHTTP_NO_ADDITIONAL_HEADERS,0,NULL,NULL,NULL,(DWORD_PTR)&cpContext);
};
WinHttpSendRequest不会阻塞,因此一旦它被执行时,函数结束。但是,WinHttpSendRequest以cpContext作为参数回调到另一个函数。所以我的问题是,doe cpContext在函数结束后被破坏?这是否会导致内存泄漏,因为无法在函数外部访问cpContext?我如何在最佳的C++实践中做到这一点?
cpContext
在函数结束时被销毁。这导致未定义的行为,因为在调用回调之前cpContext
可能会被销毁。如果您在回调中取消引用指向它的指针,则这是未定义的行为。解决方法之一是避免使用本地范围的变量:
REQUEST_CONTEXT* cpContext = new REQUEST_CONTEXT();
WinHttpSendRequest(request,WINHTTP_NO_ADDITIONAL_HEADERS,0,NULL,NULL,NULL,(DWORD_PTR)cpContext);
不要在回调函数中忘记delete
它。
泄漏将是HINTERNET
句柄,除非您在回调中关闭它。该句柄需要使用WinHttpCloseHandle
来关闭,但在异步请求处于活动状态时无法关闭它。
这取决于REQUEST_CONTEXT
是什么。如果这是一个对象,然后cpContext
被破坏。如果它是一个指针,那么只是指针被破坏。
看着你的代码,它是一个实际的对象(因为你传递的是地址),所以基于你给我们的东西,我会说它在SendRequest()
结束时被破坏,并且没有内存泄漏。
不应该很难测试,对吧?
REQUEST_CONTEXT是一个结构,它包含传入数据的缓冲区。所以也许我需要全局声明它。因为当有来自http请求的数据(由sendrequest发起)时,它会通过回调通知 – 2012-02-21 15:00:59
与所有局部变量一样,cpContext
确实超出了范围。这不是内存泄漏,但更糟。该回调将在其生命周期结束后使用对象。
如果你知道100%肯定的是,回调将被精确地调用一次,你可以用new REQUEST_CONTEXT
分配cpContext
,并从回调删除。如果你不知道,问题就更糟。您必须使用特定于API的方法来确定对象应该保持活动状态的时间。
将cpContext作为SendRequest()函数的其他本地变量分配到堆栈中。
您目前的解决方案更糟糕的是内存泄漏。这并不是说你正在泄漏记忆。事实是该对象不再存在,但您仍然持有指向该地址的指针。
从我的角度来看,这是未定义的行为。不要这样做。
您有以下选项来解决问题:
- 使用全局变量您cpContext变量。
- 通过new在堆上分配您的cpContext。
- 在另一个上下文中分配cpContext,您肯定会活下去,直到回调完成。
因此,为了解决这两个问题,我可以添加一个REQUEST_CONTEXT结构类型的全局列表,并将HINTERNETHANDLE移动到该列表。还有一个问题,因为我想了解我在做什么:requestcontexes.push_front(cpContext),将元素的副本添加到全局声明的列表中?不是对cpContext的引用? – 2012-02-21 15:20:04
是的。不要忘记使用锁来保护这个列表,因为它可能被多个线程同时访问。 – 2012-02-21 15:23:20