C ++:不了解对象销毁规则

时间:2014-06-21 12:53:37

标签: c++ scope destructor casablanca

以下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();

第二个代码片段。挂起关闭()。

    // 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();
}

第三个代码片段。挂起关闭()。

    // 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();
    }
}

Forth代码片段。挂在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();

2 个答案:

答案 0 :(得分:2)

这些示例中的每个示例的问题看起来都是相同的:请求对象的错误构造和销毁。我做错了很少见到这样的聪明才智。

简单的解决方案是:

  1. 在块内声明对象,此时将对其进行分配。
  2. 不要明确地调用析构函数(很少是个好主意)。
  3. 当块退出时,对象将被销毁。
  4. 在调用close()之前,它似乎需要被销毁,这是合理的。


    我的意思是第二个例子是唯一一个没有销毁对象的例子,它也失败了。我认为这是出于其他原因在此代码中不可见。

答案 1 :(得分:1)

免责声明:如果对该库没有任何了解,这是相当危险的

#include <iostream>
using namespace std;

class Obj {
public:
    Obj() {
        cout << "Constructor" << endl;
    }
    ~Obj() {
        cout << "Destructor" << endl;
    }
};

int main() {
    {
        Obj ea;
        ea.~Obj();
    }
    return 0;
}

输出:

Constructor 
Destructor 
Destructor

如果有资源被释放或要执行操作来清理请求,除非您执行以下步骤,否则在每种情况下都会造成很多麻烦:

  1. 通过副本(poptry_pop
  2. 获取请求
  3. 处理请求
  4. 销毁请求并清理ONCE
  5. 在上面的片段中:

    1. 从队列中复制对象,进行处理和销毁。他们每个人。的即可。
    2. 复制,处理但未销毁对象。的挂起即可。
    3. 复制,处理,销毁对象,然后再次销毁。的挂起即可。
    4. 甚至更糟比3。
    5. 复制,处理和销毁对象。 对于听众来说很好,它可能会在功能范围结束时触发问题。
    6. 对象被复制,处理,只有其中一个正在获取要求清理的析构函数 - 因此只有一个请求。 一个请求很好