【发布时间】:2014-08-12 01:39:07
【问题描述】:
以下 C++ 代码片段使用 Microsoft 的 C++ Rest SDK。我不明白为什么第一个片段有效而其他片段无效。我假设差异是由于对象破坏和范围规则造成的。我正在寻找关于为什么第一个片段有效而其他片段挂在 close() 上的解释。此外,SDK 可以做些什么来消除未来的错误。一些非常聪明的人看了片段,但从未发现问题。
第一个代码片段。该片段有效并完整显示。随后的代码片段替换其中的标记代码。请关注差异而不是其他干扰。通过在浏览器中发出单个 GET 请求并单步执行代码来测试代码。在所有情况下,request.reply() 只执行了一次。
boost::lockfree::spsc_queue<web::http::http_request, boost::lockfree::capacity<1024>> queue;
web::http::experimental::listener::http_listener listener(U("http://localhost:3901"));
listener.support([&](web::http::http_request request)
{
queue.push(request);
});
listener.open().wait();
std::cout << "listening ... hit enter to initiate shutdown." << std::endl;
std::getchar();
// BEGIN CODE IN QUESTION
while (!queue.empty())
{
web::http::http_request request;
if (queue.pop(request))
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
}
// END CODE IN QUESTION
listener.close().wait();
第二个代码片段。挂在 close() 上。
// hangs on close().wait()
web::http::http_request request;
while (queue.try_pop(request))
{
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
}
第三个代码片段。挂在 close() 上。
// hangs on close().wait(). Outer braces make no difference.
{
web::http::http_request request;
while (queue.try_pop(request))
{
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
request.~http_request();
}
}
第四个代码片段。挂在 close() 上。外大括号没有区别。
// hangs on close().wait()
{
web::http::http_request request;
while (queue.try_pop(request))
{
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
request.~http_request();
}
request.~http_request();
}
更新:支持 Matt McNabb 的解释,如果我只发出一个 GET,则以下代码有效。我只是删除了循环来处理单个 GET。需要显式调用析构函数以避免挂起,但这是不正确的做法。
web::http::http_request request;
requests.pop(request);
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
request.~http_request();
更新:循环后的显式析构函数调用使程序为单个 GET 工作。但是,两个或更多 GET 会引发异常。我不确定为什么。
web::http::http_request request;
while (queue.try_pop(request))
{
request.reply(web::http::status_codes::ServiceUnavailable, U("Service Unavailable")).wait();
}
request.~http_request();
【问题讨论】:
-
所有行
request.~http_request();导致未定义的行为,应删除。 (从技术上讲,第一个没有,但是 UB 出现在第二个,或者当函数退出时)。为同一个对象调用两次析构函数或在调用析构函数后使用该对象是未定义的行为。 -
1和2的区别是1销毁旧请求,每次都创建一个新请求;但是 2 重复使用相同的对象,而不会在每次循环迭代时破坏或创建它。如果您发布
try_pop的定义将会很有用,这样我们就可以看到它通过什么方式更新现有对象。也可能是web::http::http_request不支持try_pop使用的任何更新方法。 -
这可能是一个愚蠢的问题,但
try_pop是什么?它没有出现在boost 1.55's interface documentation ofspsc_queue -
重新。你的更新提到我的名字,去掉
request.~http_request();。它会导致未定义的行为。 “C++ 的对象销毁规则”包括只允许调用一次析构函数。 -
让我尽可能清楚地重复一遍:如果你显式调用堆栈上对象的析构函数,你将得到未定义的行为,因为析构函数将另外被第二次调用(自动)。不要那样做。相反,请关注为什么第二个示例不起作用,并尝试在每次循环迭代时构造一个新的请求对象,看看是否能解决问题。
标签: c++ scope destructor casablanca